Spring提供了一個org.springframework.beans.factory.FactoryBean工廠類接口,用戶可以通過實現該接口定制實例化Bean的邏輯。
從Spring3.0開始,FactoryBean開始支持泛型,即接口聲明改為FactoryBean<T>的形式,在該接口中共定義了以下3種方法:
T getObject():返回由FactoryBean創建的Bean的實例,若isSingleton()返回的是true,則該實例會放到Spring容器的單實例緩存池中
boolean isSingleton():確定由FactoryBean創建的Bean的作用域是singleton還是prototype
Class<T>getObjectType():返回FactoryBean創建Bean的類型
Bean的衍型注解:
@Component:用於對Bean實現類進行標注
@Repository:用於對DAO實現類進行標注
@Service:用於對Service實現類進行標注
@Controller:用於對Controller實現類進行標注
Spring提供了一個context命名空間,它提供了通過掃描類包以應用注解定義Bean的方式
<beans ...
xmlns:context="http://www.springframework.org/schema/context"
...
xsi:schemaLocation="http://www.springframework.org/schema/context/spring-context-3.0.xsd"
...
>
<context:component-scan base-package="xxx]xx.x">
聲明context命名空間后,即可通過context命名空間的component-scan的base-package屬性指定一個需要掃描的基類包,Spring容器將會掃描這個基類包里的所有類,並從類的注解信息中獲取Bean的定義信息。若希望僅掃描特定的類而非基包下所有的類,那么可以使用resource-pattern屬性過濾出特定的類
<context:component-scan base-package="xxx.xx.x" resource-pattern="xxx/*.class">
<context:include-filter>表示要包含的目標類,而<context:exclude-filter>表示要拋出在外的目標類。一個<context:component-scan>下可以擁有若干個<context:exclude-filter>和<context:include-filter>元素,這兩個元素均支持多種類型的過濾表達式。
過濾表達式:
annotation 所有標注了XxxAnnotation的類。該類型采用目標累是否標注了某個注解進行過濾。
assignable 所有繼承或擴展了XxxService的類。該類型采用目標類是否繼承或擴展某個特定類進行過濾。
aspectj 所有類名以Service結束的類及繼承或擴展它們的類。
regex 所有目錄類包下的類。該類型采用正則表達式根據目錄類的類名進行過濾
custom 采用XxxTypeFile通過代碼的方式根據過濾原則。該類必須實現org.springframework.core.type.TypeFilter
Spring通過@Autowired注解實現Bean的依賴注入。@Autowired默認按類型匹配的方式,在容器查找匹配的bean,當且僅當僅有一個匹配的Bean時,Spring將其注入到@Autowired標注變量中。如果容器中沒喲一個和標注變量類型匹配的Bean,Spring容器啟動時將報NoSuchBeanDefinitionException的異常。若希望Spring即使找不到匹配的Bean完成注入也不要拋出異常,則可使用@Autowired(required=false)進行標注。默認情況下,required的屬性值為true。若容器中有一個以上匹配的Bean時,則可以通過@Qualifier注解限定Bean的名稱
@Autowired
@Qualifier("userDao")
private UserDao userDao;//若容器中存在userDao和otherUserDao
@Autowired還可以對成員變量及方法的入參進行標注,也可對入參標注@Qualifier以指定注入Bean的名稱。
一般情況下,在Spring容器中大部分的Bean都是單實例的,所以我們一般都無須通過@Repository、@Service等注解的value屬性為Bean指定名稱,也無須使用@Qualifier按名稱進行注入。
若Spring發現變量是一個集合類,則它會將容器中匹配集合元素類型的所有Bean都注入進來。
Spring還支持JSR250中定義的@Resource和JSR-330中定義的@Inject注解,這兩個注解都是對類變量及方法入參提供自動注入的功能。@Resource要求提供一個Bean名稱的屬性,若屬性為空,則自動采用標注處的變量名或方法作為Bean的名稱。
@Component
public class Boss{
private Car car;
@Resource("car")
private void setCar(Car car){
this.car = car ;
}
}
@Autowired默認按類型匹配注入Bean,@Resource則按名稱匹配注入Bean。而@Inject也是按類型匹配注入Bean的,只不過它沒有required屬性。
Spring為注解配置提供了一個@Scope的注解,通過它可以顯示指定Bean的作用范圍。
@Scope("prototype")
@Component
Spring支持JSR-250中定義的@PostConstruct和@PreDestroy注解,在Spring中他們相當於initmethod和destroy-method屬性功能。但可以在一個Bean中定義多個@PostConstruce和@PreDestroy。
JavaConfig是Spring的一個子項目,它旨在通過Java類的方式提供Bean的定義信息。普通的POJO只要標注@Configuration注解,就可以為Spring容器提供Bean定義的信息了,每個標注了@Bean的類方法都相當於提供一個Bean的定義信息。
@Configuration
public class AppConf{
@Bean
public UserDao userDao(){
return new UserDao();
}
}
Spring提供一個AnnotationConfigApplicationContext類,它能夠直接通過標注@Configuration的Java類啟動Spring容器。
public class JavaConfigTest{
public static void main(String[] args){
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConf.class);
LogonService logonService = ctx.getBean(LogonService.class);
}
}
通過AnnotationConfigApplicationContext類的構造函數直接傳入標注@Configuration的Java類,直接用該類中提供的Bean的定義信息啟動Spring。此外,AnnotationConfigApplicationContext還支持通過編碼的方式加載多個@Configuration配置類,然后通過刷新容器應用這些配置類。
public class JavaConfigTest{
public static void main(String[] args){
ApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(DaoConfi.class);
ctx.register(ServiceConfig.class);
ctx.refresh();
LogonService logonService = ctx.getBean(LogonService.class);
}
}
也可以通過@Import將多個配置類組裝到一個配置類中。
@Configuration
@Import(DaoConfig.class)
public class ServiceConfig{
@Bean
public LogonService logonService(){
LogonService logonService = new LogonService();
return logonService;
}
}
在@Configuration配置類中可以通過@ImportResource引入XML配置文件,在配置類中即可直接通過@Autowired引用XML配置文件中定義Bean。
@Configuration
@ImportResource("classpath:xxx/xx/x.xml")
Bean不同配置方式的比較
Bean的定義
基於XML配置:在XML中通過<bean>元素定義Bean
基於注解配置:在Bean實現類出通過標注@Component或衍型類(@Service、@Repository、@Controller)定義Bean。
基於Java類配置:在標注了@Configuration的Java類中,通過在類方法上標注@Bean定義一個Bean。方法必須提供Bean的實例化邏輯。
Bean名稱
基於XML配置:通過<bean>的id或name屬性定義
基於注解配置:通過注解的value屬性定義。默認名成為小寫字母打頭的類名
基於Java類配置:通過@Bean的name屬性定義
Bean注入
基於XML配置:通過<property>子元素或通過p命名空間的動態屬性
基於注解配置:通過在成員變量或方法入參出標注@Autowired,按類型匹配自動注入,還可配合使用@Qualifier按名稱匹配注入
基於Java類配置:比較靈活,可以通過在方法處通過@Autowired使方法入參綁定Bean,然后在方法中通過代碼進行注入,還可以通過調用配置類的@Bean方法進行注入
Bean生命過程方法
基於XML配置: 通過<bean>的init-method和destroy-method屬性指定Bean實現類的方法名,最多只能指定一個初始化方法和一個銷毀方法。
基於注解配置: 通過在目標方法上標注@PostContructor和@PreDestroy注解指定初始化和銷毀方法,可以定義任意多個方法
基於Java類配置: 通過@Bean的initMethod或destroyMethod指定一個初始化或銷毀方法。對於初始化方法來說,可以直接在方法內部通過代碼的靈活定義初始化邏輯
Bean作用范圍
基於XML配置: 通過<bean>的scope屬性指定
基於注解配置: 通過在類定義處標注@Scope指定
基於Java類配置: 通過在Bean方法定義處標注@Scope指定
Bean延遲初始化
基於XML配置: 通過<bean>的lazy-init屬性指定,默認為default,繼承與<beans>的default-lazy-init設置,默認為false
基於注解配置: 通過在類定義處標注@Lazy指定
基於Java類配置: 通過在Bean方法定義處標注@Lazy指定
基於XML配置使用場合:Bean實現類來源於第三方類庫,因無法在類中標注注解,通過XML配置方式較好;命名空間的配置,只能采用基於XML的配置
基於注解配置: Bean的實現類是當前項目開發的,可以直接在Java類中使用基於注解的配置
基於Java類配置: 基於Java類配置的又是在於可以通過代碼方式控制Bean初始化的整體邏輯。若實例化Bean的邏輯比較復雜,則比較適合基於Java類配置的方式
