Spring最成功的是其提出的理念羡洁,而不是技術(shù)本身。它所依賴的兩個核心理念,一個是控制反轉(zhuǎn)(Inversion of Control权纤,IoC)钓简,另一個是面向切面編程(Aspect Oriented Programming,AOP)
IoC是一種通過描述來生成或者獲取對象(Bean)的技術(shù)汹想,這個技術(shù)不是Spring甚至不是Java獨(dú)有的外邓。平時最熟悉的是使用new關(guān)鍵字來創(chuàng)建對象,而在Spring中則不是古掏,它是通過描述來創(chuàng)建對象损话。Spingt Boot中建議使用注解描述生成對象而不是使用XML。
Spring中把每一個需要管理的對象稱為Spring Bean(簡稱Bean)槽唾,管理這些Bean的容器稱為Spring IoC容器(或者簡稱IoC容器)丧枪。IoC容器具備兩個基本的功能:通過描述管理Bean(包括發(fā)布和獲取Bean)和通過描述完成Bean之間的依賴關(guān)系。
Spring IoC容器總庞萍,可以按類型(by type)或者按名稱(by name)獲取Bean拧烦,默認(rèn)情況下Bean都是以單例存在的。
IoC裝配Bean
使用@Bean注解裝配Bean
@Configuration
public class BeanConfig {
@Bean(name = "user")
public User initUser() {
User user = new User();
user.setUsername("Jack");
user.setAge(18);
return user;
}
}
@Configuration 表示這是一個Java配置文件钝计,Spring容器會根據(jù)它來生成IoC容器去裝配Bean
@Bean 表示將initUser方法返回的POJO裝配到IoC容器中恋博,屬性name定義Bean的名稱,如果沒有設(shè)置該屬性私恬,則默認(rèn)使用方法名稱initUser作為Bean的名稱保存到Spring IoC容器中
通過掃描裝配Bean
如果使用@Bean一個個的裝配债沮,將是一件很麻煩的事情,Spring也意識到了這點(diǎn)本鸣,允許使用掃描的方式進(jìn)行裝配秦士,使用的注解是@Component和@ComponentScan,@Component標(biāo)明哪個類被掃描進(jìn)入Spring IoC容器永高,而@ComponentScan則是標(biāo)明采用何種策略掃描裝配Bean
package com.test.example.config;
@Component("user")
public class User {
@Value("Jack")
private String username;
@Value("18")
private int age;
}
@Component標(biāo)明該類將被Spring IoC容器掃描裝配隧土,其中配置的user則是Bean的名稱,如果不配置命爬,則IoC容器默認(rèn)會把類名第一個字母作為小寫曹傀,其他不變作為Bean名稱
@Value 指定具體的值,使得Spring IoC給予對應(yīng)的屬性注入對應(yīng)的值
為了Spring IoC容器裝配這個類饲宛,調(diào)整BeanConfig
package com.test.example.config;
@Configuration
@ComponentScan
public class BeanConfig {
}
@ComponentScan 標(biāo)明會進(jìn)行掃描皆愉,默認(rèn)只是掃描BeanConfig所在的當(dāng)前package和子package,可以觀察到User也在該package下面艇抠,但是這樣設(shè)置太不合理幕庐,為了更加合理,運(yùn)行@ComponentScan掃描自定義的包
@ComponentScan(basePackages = {" com.test.example.pojo"})
包名可以采用正則表達(dá)式匹配家淤,但是這個也有不合理的地方异剥,比如不想加載某些Bean,比如定義一個UserService類絮重,將它標(biāo)記為@Service(該注解已經(jīng)注入了@Component)服務(wù)類冤寿,則也會被Spring掃描裝配到IoC容器中歹苦,如果不希望這些服務(wù)類被裝配,則可以通過設(shè)置excludeFilters
@ComponentScan(basePackages = {" com.test.example.*", excludeFilters = {@Filter(classes = {Service.class})}})
由于加入excludeFilters設(shè)置督怜,則使用@Service注解的服務(wù)類不會被掃描注入
自定義第三方Bean
實(shí)際項(xiàng)目中經(jīng)常需要引入許多第三方的包殴瘦,并且希望把第三方包的類對象放入到Spring IoC容器中,這時需要使用@Bean注解
定義一個數(shù)據(jù)源
@Bean(name = "dataSource")
public DataSource getDataSource() {
Properties props = new Properties();
props.setProperty("driver", "com.mysql.jdbc.Driver");
props.setProperty("url", "jdbc:mysql://localhost:3306/test");
props.setProperty("username", "root");
props.setProperty("password", "root");
DataSource dataSource = null;
try {
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
通過@Bean的name配置Bean名稱為“dataSource”号杠,如果不設(shè)置name屬性蚪腋,默認(rèn)會使用方法名稱作為Bean名稱保存到IoC容器中。
上半部分主要討論了Bean如何裝載到IoC容器中姨蟋,對于如何獲取以及Bean之間的依賴屉凯,在Spring IoC概念中稱為依賴注入(Dependency Injection,DI)
依賴注入DI
@Autowired
Spring中最常用注解之一芬探,可以標(biāo)注屬性神得、方法、參數(shù)偷仿。
根據(jù)類型(by type)獲取Bean哩簿,@Autowired是一個默認(rèn)必須找到對應(yīng)Bean的注解,如果不確定其標(biāo)注的屬性一定存在并且允許被標(biāo)注的屬性為Null酝静,可以設(shè)置required屬性為false
@Autowired(require = false)
消除歧義性 @Primary和@Qualifier
@Primary是一個修改優(yōu)先權(quán)的注解节榜,其目的當(dāng)發(fā)現(xiàn)有多個同類型的Bean時,高速IoC容器優(yōu)先使用該注解標(biāo)記的Bean别智,但是它也可以被標(biāo)注到多個Bean上宗苍,這時IoC容器還是無法區(qū)分要采用哪個Bean實(shí)例,此時需要使用@Qualifier的value來進(jìn)行設(shè)置
@Qualifier和@Autowired組合在一起就是通過類型和名稱一起找到Bean薄榛,Bean的名稱在IoC容器中是唯一的讳窟,如
@Autowired
@Qualifier("dog")
private Animal animal = null;
帶有參數(shù)的構(gòu)造方法類裝配
public ConstructorAnimal(@Autowired @Qualifier("dog") Animal animal) {
...
}