@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注解也不会被容器使用。