本文基于Spring 5.2.7
org.springframework.context.annotation.Configuration
始自 Spring 3.0
标识一个声明一个或多个@Bean方法的的类,这个类会被Spring容器处理以生成对应的bean definitions和service requests。例子如下:
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
// instantiate, configure and return bean ...
}
}
@Configuration类通常被用作启动引导类,通过AnnotationConfigApplicationContext或支持web的变体AnnotationConfigWebApplicationContext,一个简单的使用例子如下:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
MyBean myBean = ctx.getBean(MyBean.class);
// use myBean ...
查阅读AnnotationConfigApplicationContext文档获取更多细节,查阅AnnotationConfigWebApplicationContext文档获取有关servlet 容器的web configuration细节。
作为通过AnnotationConfigApplicationContext直接注册@Configuration类的替代,@Configuration类可以在Spring XML文件中被声明为普通的<bean>定义。如下:
<beans>
<context:annotation-config/>
<bean class="com.acme.AppConfig"/>
</beans>
上面的例子中,需使用<context:annotation-config/>,他能让ConfigurationClassPostProcessor和其他相关注解的post processors工作,用以处理@Configuration类。
@Configuration定义上就关联了@Component,因此@Configuration类是组件扫描(Spring XML中使用<context:component-scan/>)的候选者,同时也可以像其他常规@Component一样利用@Autowired/@Inject。特别地,如果当前提供了单个构造函数,自动装配语义将被透明的应用到这个构造函数上:
@Configuration
public class AppConfig {
private final SomeBean someBean;
public AppConfig(SomeBean someBean) {
this.someBean = someBean;
}
// @Bean definition using "SomeBean"
}
@Configuration类不仅仅只被component scanning引导, 而且还能使用@ComponentScan通过自身进行component scanning:
@Configuration
@ComponentScan("com.acme.app.services")
public class AppConfig {
// various @Bean definitions ...
}
查阅@ComponentScan文档获取更多细节。
外部值可以通过注入Spring Environment到@Configuration类中被查找到,例如,使用@Autowired注解:
@Configuration
public class AppConfig {
@Autowired Environment env;
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
myBean.setName(env.getProperty("bean.name"));
return myBean;
}
}
一个或多个properties文件中的属性被解析到Environment,且@Configuration类能够通过使用@PropertySource注解将properties文件添加到Environment中:
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
@Inject Environment env;
@Bean
public MyBean myBean() {
return new MyBean(env.getProperty("bean.name"));
}
}
外部值可以通过使用@Value注解注入到@Configuration类中:
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
@Value("${bean.name}") String beanName;
@Bean
public MyBean myBean() {
return new MyBean(beanName);
}
}
这种方法通常和Spring的PropertySourcesPlaceholderConfigurer一起使用。PropertySourcesPlaceholderConfigurer在XML配置下可以通过<context:property-placeholder/>启动,或者在@Configuration类中声明一个静态@Bean方法(可以查阅@Bean的文档获取更多相关细节)。但是请注意,通过静态@Bean方法显示注册PropertySourcesPlaceholderConfigurer的行为只在需要自定义配置的情况下使用,如自定义占位符语法等。特别地,如果ApplicationContext中没有内置的bean post-processor(例如PropertySourcesPlaceholderConfigurer)被注册,Spring会注册一个默认的解析properties文件的内置解析器到Environment中。
@Configuration类可以通过@Import注解聚合,就像XML中使用<import>一样。因为@Configuration对象是作为Spring beans被管理在Spring容器中的,imported configurations会被注入。例如,通过构造函数注入:
@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和导入的DatabaseConfig能够同时被引导只能在一种情况下发生,那就是AppConfig这样注册:new AnnotationConfigApplicationContext(AppConfig.class)
@Configuration可以通过指定@Profile注解来表明他们在给定的profile或profiles活动时才被处理。
@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内使用相同效果的变量:
@Configuration
public class ProfileDatabaseConfig {
@Bean("dataSource")
@Profile("development")
public DataSource embeddedDatabase() { ... }
@Bean("dataSource")
@Profile("production")
public DataSource productionDatabase() { ... }
}
如上面提到,@Configuration类可以被声明如同Spring XML中<bean>。可以使用@ImportResource注解引入Spring XML文件到@Configuration类中。从XML中引入的bean definitions可以被注入,通过使用@Inject注解:
@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);
}
}
@Configuration可以被另一个嵌套,如下:
@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();
}
}
}
当引导这样的逻辑时,只需针对ApplicationContext注册AppConfig即可。作为嵌套的@Configuration的优势,DatabaseConfig会被自动注册。这避免了当AppConfig和DatabaseConfig之间关系清晰时还使用@Import注解。
同样注意,嵌套@Configuration类能够像@Profile一样在外层@Configuration类提供2种选择的效果。
默认情况下,@Bean方法会在容器引导是急加载。为了避免这种情况,@Configuration可以联合@Lazy一起使用,表明@Configuration类里的所有@Bean方法是懒加载的,注意,@Lazy也可以单独用在没有@Bean方法上。
spring-test模块中的TestContext framework提供了@ContextConfiguration注解,他能接收component引用数组——典型如@Configuration或@Component类型:
@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 ...
}
}
Spring特性诸如:异步方法执行,定时任务执行,声明事务管理,甚至Spring MVC等,他们都能通过@Configuration类使用各自的@Enable注解开启,查阅@EnableAsync,@EnableScheduling,@EnableTransactionManagement,@EnableAspectJAutoProxy,@EnableWebMvc获取更多细节。
@Configuration类必须作为类提供(如不能是factory method返回),允许是运行时生成的增强子类。
@Configuration不能是final(因为运行时要通过生成子类增强),除非proxyBeanMethods被设置为false,表明运行时不会生成子类增强。
@Configuration不能是局部类(不能在方法中声明@Configuration类)。
任何嵌套的@Configuration必须是static
@Bean方法不能反过来创建@Configuration类(任何这样的Bean会被当成常规bean对待,他的@Configuration注解也不会被检测到)