在定義 JavaConfig 時,@ComponentScan
預設會掃描同一套件或其子套件中,是否有標註相關元件,你也可以指定要掃描的套件,例如 @ComponentScan("cc.openhome.controller")
,如果有多個套件要掃描,可以使用 basePackages
指定,例如:
@ComponentScan(basePackages = {"cc.openhome.model", "cc.openhome.controller"})
如果要指定掃描元件類別及其所在套件,可以使用 basePackageClasses
,例如:
@ComponentScan(basePackageClasses = {
cc.openhome.model.UserService.class,
cc.openhome.controller.AccountController.class
})
如果想進一步包含或排除某些元件,可以指定 includeFilters
、excludeFilters
,指定時使用 ComponentScan.Filter
來設定,最基本的是設定 classes
,例如:
@ComponentScan(
basePackages = {"cc.openhome.model", "cc.openhome.controller"},
excludeFilters = {@Filter(classes = {MailService.class})}
)
使用 @Bean
定義 Bean 的時候,預設會使用方法的名稱作為 Bean 的名稱,可以使用 ApplicationContext
的 getBean
指定 Bean 名稱來取得對應的 Bean,不過傳回型態為 Object
,就這點來看,透過指定類別還是比較方便安全的。
使用 @Bean
時,可以自行指定名稱,例如 @Bean("embeddedDatasource")
或者是 @Bean(name = "embeddedDatasource")
,實際上可以指定多個名稱,例如 @Bean({"d1", "d2"})
。
如果原始碼在專案的控制之中,標註 @Component
時也可以指定名稱,例如 @Component("userService")
,若不指定,預設為類別名稱首字母小寫。
如果 Bean 本身具有初始或清除資源的方法,可以透過 initMethod
、destroyMethod
指定方法名稱,例如〈設定 Profile〉中就有以下的設定:
@Bean(destroyMethod="shutdown")
public DataSource dataSource(){
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:testData.sql")
.build();
}
@Bean
可以搭配 @Lazy
來標註,該 Bean 就延遲初始。對於 Spring 管理的 Bean,預設都是單例(Singleton),也就是整個應用程式只存在一個實例,如果想要每次取得 Bean 時,都必須建立一個新的實例,可以標註 @Scope("prototype")
或 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
(ConfigurableBeanFactory.SCOPE_PROTOTYPE
只是個字串值 "prototype"
)。
如果原始碼在專案的控制之中,也可以在被 @Component
標註的元件中標註 @Scope("prototype")
。
在複雜的環境下,也許你對想要依某些條件,決定某個 Bean 是否生成,這時可以使用 @Conditional
,它可以指定實現了 Condition
介面的類別,例如:
@Bean(destroyMethod="shutdown")
@Conditional(DbCond.class)
public DataSource dataSource(){
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:testData.sql")
.build();
}
DbCond
是實現了 Condition
的類別,其實作的 matches(ConditionContext context, AnnotatedTypeMetadata metadata)
方法,可以傳回 true
、false
,告知 Spring 是否建立該 Bean。
每個標註的相關設定,都可以在 API 文件上找到說明,如果有某個需求,應該試著自行查看 API 文件,看看有無對應的屬性可以設定。例如,也許想要延遲初始 @ComponentScan
掃描到的元件,就可以在 ComponentScan API 文件找找看,或許有個屬性就可以滿足需求(實際上就是 lazyInit
屬性)。