天天看點

Spring注解之@Configuration和@Bean使用詳解

前言

Spring3.0之前要使用Spring必須要有一個xml配置檔案,而Spring3.0之後注解慢慢登上舞台,通過注解@Configuration和@Bean可以完全搞定。此時,注解和xml配置形成了互相協作與競争的關系。随着Springboot的推廣,注解的使用在Spring中大放光彩,xml的輝煌一去不返。通過注解,簡化了配置,提升了編碼效率。

Spring 3.0新增了另外兩個實作類:AnnotationConfigApplicationContext 和 AnnotationConfigWebApplicationContext。它們是為注解而生,直接依賴于注解作為容器配置資訊來源的IoC容器初始化類。AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的web版本,其用法與後者相比幾乎沒有什麼差别。

今天這篇文章帶大家學習@Configuration和@Bean的使用,并通過具體的執行個體體驗一下注解的友善快捷。如果你的項目中還未曾使用此類注解,說明你的技術棧已經在被淘汰的邊緣。

基于Java類的配置選項

Spring 3.0引入了注解,配置檔案的載體就從xml檔案轉換為了Java類,Java類就是一個普通的類,除了命名建議以“**Config”結尾友善識别外,Spring對其有一定的約定條件。

  • 配置類不能是 final 類(沒法動态代理)。
  • 配置類必須是非本地的(即不能将配置類定義在其他類的方法内部,不能是private)。
  • 配置類必須有一個無參構造函數。

基本使用方法

符合上述條件的類,就可以使用@Configuration來進行注解,表示這個類可以使用Spring IoC容器作為bean定義的來源。@Bean注解在該類的方法上,AnnotationConfigApplicationContext将配置類中标注了@Bean的方法的傳回值識别為Spring Bean,并注冊到容器中,歸入IoC容器管理。

@Configuration的作用等價于XML配置中的标簽,@Bean的作用等價于XML配置中的标簽。下面代碼完成了一個簡單的示例。

  1. @Configuration

  2. public class DataSourceConfig {

  3.    @Bean

  4.    public MysqlDataSource mysqlDataSource() {

  5.        return new MysqlDataSource();

  6.    }

  7.    @Bean(name = "oracleDataSource")

  8.    public OracleDataSource oracleDataSource() {

  9.        return new OracleDataSource();

  10.    }

  11. }

Spring在解析該類時,會識别出标注@Bean的所有方法,執行并将方法的傳回值(MysqlDataSource和OracleDataSource對象)注冊到IoC容器中。預設情況下,方法名即為Bean的名字。與以上配置等價的XML配置如下:

  1. <bean id="mysqlDataSource" class="**.MysqlDataSource"/>

  2. <bean id="oracleDataSource" class="**.OracleDataSource"/>

@Configuration的屬性

@Configuration的定義代碼:

  1. @Target({ElementType.TYPE})

  2. @Retention(RetentionPolicy.RUNTIME)

  3. @Documented

  4. @Component

  5. public @interface Configuration {

  6.    String value() default "";

  7. }

@Configuration注解本身定義時被@Component标注了,是以本質上來說@Configuration也是一個@Component,隻不過我們在具體使用的過程中基本用不到它的執行個體化對象。

@Bean屬性

@Bean注解的具體代碼定義:

  1. @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})

  2. @Retention(RetentionPolicy.RUNTIME)

  3. @Documented

  4. public @interface Bean {

  5.    @AliasFor("name")

  6.    String[] value() default {};

  7.    @AliasFor("value")

  8.    String[] name() default {};

  9.    Autowire autowire() default Autowire.NO;

  10.    String initMethod() default "";

  11.    String destroyMethod() default "(inferred)";

  12. }

可以看出@Bean具有以下屬性:

  • name :指定一個或者多個Bean的名字。等價于XML配置中的name屬性,示例中的@Bean(name = "oracleDataSource")。
  • initMethod:容器在初始化完Bean之後,會調用該屬性指定的方法。等價于XML配置中的init-method屬性。
  • destroyMethod:該屬性與initMethod功能相似,在容器銷毀Bean之前,會調用該屬性指定的方法。等價于XML配置中的destroy-method屬性。
  • autowire:指定Bean屬性的自動裝配政策,取值是Autowire類型的三個靜态屬性。Autowire.BYNAME,Autowire.BYTYPE,Autowire.NO。與XML配置中的autowire屬性的取值相比,少了constructor,因為 constructor在這裡已經沒有意義了。

@Bean預設是單例模式,并且沒有提供指定作用域的屬性,可以通過@Scope來實作該功能。

  1. @Bean

  2. @Scope("prototype")

  3. public MysqlDataSource mysqlDataSource() {

  4.    return new MysqlDataSource();

  5. }

Spring掃描加載

當配置完Spring掃描指定包及其子包中的類時,會識别所有标記了@Component、@Controller、@Service、@Repository注解的類,由于@Configuration注解本身也用@Component标注了,Spring将能夠識别出 @Configuration标注類。

執行個體

現在對上面的示例進行單元測試,其中MysqlDataSource和OracleDataSource類中分别提供了列印日志的方法:

  1. public void print(){

  2.    System.out.println("I am MysqlDataSource!");

  3. }

  4. public void print(){

  5.    System.out.println("I am OracleDataSource!");

  6. }

指定單元測試的代碼如下:

  1. public class ConfigBeanTest {

  2.    @Test

  3.    public static void testGetBean() {

  4.        ApplicationContext ctx = new AnnotationConfigApplicationContext(DataSourceConfig.class);

  5.        MysqlDataSource mysqlDataSource = ctx.getBean(MysqlDataSource.class);

  6.        mysqlDataSource.print();

  7.    }

  8. }

當執行單元測試,成功列印出:

  1. I am MysqlDataSource!

實戰技巧

如果我們在DataSourceConfig中再添加一個方法,這個方法用到了前面執行個體化的兩個bean對象,那麼該如何處理?正常的想法是在DataSourceConfig中添加如下代碼,然後再直接使用屬性:

  1. @Autowired

  2. private MysqlDataSource mysqlDataSource;

其實不必如此,直接調用方法mysqlDataSource()方法即可。比如,需要新增下面類的執行個體化:

  1. public class CommonDataSource {

  2.    private MysqlDataSource mysqlDataSource;

  3.    private OracleDataSource oracleDataSource;

  4.    // 省略getter/setter方法

  5. }

那麼,我們隻用在DataSourceConfig中添加如下代碼即可:

  1. @Bean

  2. public CommonDataSource commonDataSource() {

  3.    CommonDataSource commonDataSource = new CommonDataSource();

  4.    commonDataSource.setMysqlDataSource(mysqlDataSource());

  5.    commonDataSource.setOracleDataSource(oracleDataSource());

  6.    return commonDataSource;

  7. }

小結

上一篇: Hadoop+HBase
下一篇: IIS