@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文档,转载请标明出处。