@Configuration注解标识的类中声明了1个或者多个@Bean方法,Spring容器可以使用这些方法来注入Bean,比如:

@Configuration
public class AppConfig {
  //这个方法就向Spring容器注入了一个类型是MyBean名字是myBean的Bean
  @Bean
  public MyBean myBean() {
     // instantiate, configure and return bean ...
  }
}

@Configuration类一般是由AnnotationConfigApplicationContext或者它的web变种AnnotationConfigWebApplicationContext来处理的,比如:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//这是configuration类
ctx.register(AppConfig.class);
ctx.refresh();
MyBean myBean = ctx.getBean(MyBean.class);
// use myBean ...

也可以用以XML方式引入,就跟引入普通的Bean是一样的:

<beans>
  <context:annotation-config/>
  <!--也可以这样加载configuration类-->
  <bean class="com.acme.AppConfig"/>
</beans>

上例中,为了启用ConfigurationClassPostProcessor和其他的注解相关的Post Processor来处理@Configuration,需要添加context:annotation-config/。

组件扫描的方式使用

@Configuration上面添加了@Component元注解,因此, @Configuration是支持组件扫描的(一般要添加context:component-scan/ ) ,它跟其他普通的Component一样也支持@Autowired/@Inject,如果@Configuration的类有一个构造函数,也支持构造函数自动注入,比如:

@Configuration
public class AppConfig {
  private final SomeBean someBean;
  //构造函数注入
  public AppConfig(SomeBean someBean) {
    this.someBean = someBean;
  }
  //注入另一个bean
  @Autowired
  private AnotherBean1 anotherBean1;
  
  //注入另一个bean
  @Resource
  private AnotherBean2 anotherBean2;
  // @Bean definition using "SomeBean"
}

@Configuration 类不仅可以被扫描到,它自己也可以配置@ComponentScan注解去做组件扫描。

@Configuration
//做组件扫描
@ComponentScan("com.acme.app.services")
public class AppConfig {
  // various @Bean definitions ...
}

在@Configuration中使用property

使用Environment获取property

可以把org.springframework.core.env.Environment注入到@Configuration里面来获取property值,比如可以使用@Autowired注入:

@Configuration
public class AppConfig {
  //注入Environment 
  @Autowired 
  Environment env;
  @Bean
  public MyBean myBean() {
    MyBean myBean = new MyBean();
    myBean.setName(env.getProperty("bean.name"));
    return myBean;
  }
}

通过Environment获取的property可以存在于多个"property source" 对象中,@Configuration类本身也可以使用@PropertySource来提供"property source":

@Configuration
//引入property文件
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
  @Inject 
  Environment env;
  @Bean
  public MyBean myBean() {
    return new MyBean(env.getProperty("bean.name"));
  }
}
使用@Value注解获取property
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
  @Value("${bean.name}") 
  String beanName;
  @Bean
  public MyBean myBean() {
    return new MyBean(beanName);
  }
}

这种方式经常和PropertySourcesPlaceholderConfigurer一起使用,PropertySourcesPlaceholderConfigurer可以通过配置context:property-placeholder/来自动启用,也可以在@Configuration类中用@Bean明确来启用。

注意,只有当你需要自定义占位符等场景才需要用@Bean来注册PropertySourcesPlaceholderConfigurer,如果ApplicationContext中没有明确注册PropertySourcesPlaceholderConfigurer,Spring容器会在Environment中自动注册一个默认的property解析器。

使用@EnableConfigurationProperties

这种方式可以引入@ConfigurationProperties标识的注解类,比如:

@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {
    ...
}
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {
    ...
}

组合@Configuration类

使用@Import注解

可以使用@Import注解组合多个@Configuration类,就跟在xml中使用 引入别的配置文件一样。因为@Configuration对象是被Spring容器当成Bean来管理的,被引入的Configuration类也可以被容器管理和注入,比如可以用构造函数注入的方式:

//这是一个@Configuration类
@Configuration
public class DatabaseConfig {
  @Bean
  public DataSource dataSource() {
  // instantiate, configure and return DataSource
  }
}
//这里可以引用上面的配置类
@Configuration
@Import(DatabaseConfig.class)
public class AppConfig {
  private final DatabaseConfig dataConfig;
  public AppConfig(DatabaseConfig dataConfig) {
    this.dataConfig = dataConfig;
  }
  @Bean
  public MyBean myBean() {
    // reference the dataSource() bean method
    return new MyBean(dataConfig.dataSource());
  }
}

现在只需要在容器中注册AppConfig就可以同时注册AppConfig和DatabaseConfig了,比如:

new AnnotationConfigApplicationContext(AppConfig.class);
使用@Profile注解

@Configuration可以跟@Profile一起使用,说明只有在给定的profile下@Configuration 才能生效:

@Profile("development")
@Configuration
public class EmbeddedDatabaseConfig {
  @Bean
  public DataSource dataSource() {
    // instantiate, configure and return embedded DataSource
  }
}
@Profile("production")
@Configuration
public class ProductionDatabaseConfig {
  @Bean
  public DataSource dataSource() {
    // instantiate, configure and return production DataSource
  }
}

此外还可以在@Bean 方法级别上设置profile,比如:

@Configuration
public class ProfileDatabaseConfig {
  @Bean("dataSource")
  @Profile("development")
  public DataSource embeddedDatabase() { ... }
  @Bean("dataSource")
  @Profile("production")
  public DataSource productionDatabase() { ... }
}
使用@ImportResource注解引入Spring的xml配置

@Configuration类可以在xml中像普通的bean那样定义,同时也可以在@Configuration类中使用@ImportResource引入xml配置文件,被引入的xml中定义的bean也可以被注入,比如:

@Configuration
@ImportResource("classpath:/com/acme/database-config.xml")
public class AppConfig {
  @Inject DataSource dataSource; // from XML
  @Bean
  public MyBean myBean() {
    // inject the XML-defined dataSource bean
    return new MyBean(this.dataSource);
  }
}

虽然可以,但是不推荐,相当于是一种兼容xml的做法。

嵌套的@Configuration类

@Configuration类可以内嵌在别的@Configuration类当中(比如mybatis-spring-boot-starter的MybatisAutoConfiguration):

@Configuration
public class AppConfig {
  @Inject DataSource dataSource;
  @Bean
  public MyBean myBean() {
    return new MyBean(dataSource);
  }
  @Configuration
  static class DatabaseConfig {
    @Bean
    DataSource dataSource() {
      return new EmbeddedDatabaseBuilder().build();
    }
  }
}

只需要注册AppConfig就可以同时把AppConfig和DatabaseConfig一块注入到容器中,内嵌的DatabaseConfig会被自动注册,这种方式就避免了使用@Import。
注意这种内嵌的@Configuration类的方式也可以和 @Profile一起使用来提供同一个bean的多种实现。

配置延迟初始化

默认情况下,@Bean方法是在容器启动时立即加载的,@Configuration可以和@Lazy一起使用,表明所有的@Bean 方法都是延迟初始化的,当然@Lazy也可以标注在单个@Bean方法上。

@Configuration类如何做测试

Spring的Test框架提供了@ContextConfiguration注解,他可以接受

// @Configuration类:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {AppConfig.class, DatabaseConfig.class})
public class MyTests {
  @Autowired MyBean myBean;
  @Autowired DataSource dataSource;
  @Test
  public void test() {
  // assertions against myBean ...
  }
}

使用@Enable启用Spring的内置的特性

Spring的一些特性比如异步方法调用、任务调度、注解驱动的事务管理、甚至是SpringMVC都可以通过配置@Configuration来启用,详细信息可以参考@EnableAsync, @EnableScheduling, @EnableTransactionManagement, @EnableAspectJAutoProxy @EnableWebMvc。

@Configuration类的一些限制

  • @Configuration类必须是class,不能是工厂方法返回的实例,允许运行时增强。
  • @Configuration类一定不能是final的。
  • @Configuration类一定不能是local的(不能在方法内部定义)
  • @Configuration类的内嵌的配置类必须是static的。
  • @Bean方法不能创建配置类,@Bean方法定义的bean只是普通的Bean,即使有@Configuration注解也不会被容器使用。

以上内容翻译自@Configuration的Javadoc文档,转载请标明出处。
扫一扫关注微信公众号

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐