基本用途
從Spring3.0,@Configuration用於定義配置類,可替換xml配置文件,被注解的類內部包含有一個或多個被@Bean注解的方法,這些方法將會被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類進行掃描,並用於構建bean定義,初始化Spring容器。例如:
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
// instantiate, configure and return bean ...
}
}
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);//加載配置類
ctx.refresh();//刷新並創建容器
MyBean myBean = ctx.getBean(MyBean.class);
// use myBean ...
注意:
@Configuration不可以是final類型;
@Configuration不可以是匿名類;
嵌套的configuration必須是靜態類。
加載配置類方法
硬編碼,例如ctx.register(AppConfig.class);
使用xml配置
<beans>
//這個注解用於啟用ConfigurationClassPostProcessor等后置處理器,以加載以下類到容器。
<context:annotation-config/>
<bean class="com.acme.AppConfig"/>
</beans>
XmlWebApplicationContext xmlWebApplicationContext = new XmlWebApplicationContext();
xmlWebApplicationContext.setConfigLocation("abc.xml");
1
組件掃描。@Configuration本身是繼承自@Component,因此也可以和正常被@Component一樣被掃描到,或使用autowired。
package com.acme.app.services
@Configuration
public class AppConfig {
private final SomeBean someBean;
//這里可以通過Spring注入someBean
public AppConfig(SomeBean someBean) {
this.someBean = someBean;
}
// @Bean definition using "SomeBean"
}
要想AppConfig被掃描到,可以
@Configuration
@ComponentScan("com.acme.app.services")
public class RootConfig {
// various @Bean definitions ...
}
使用外部變量
注入Environment屬性(可用於獲取系統、JVM等環境變量),並配合@PropertySources注解,加載配置文件,使用@Value加載配置項。
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
@Inject Environment env;
//PropertySourcesPlaceholderConfigurer,usually enabled via XML with <context:property-placeholder/>
@Value("${bean.name}") String beanName;
@Bean
public MyBean myBean() {
return new MyBean(env.getProperty("bean.name"));
}
}
組合多個配置類
類似於xml的\標簽,可以使用@Import組合多個配置類,例如:
@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());
}
}
//最后只需要導入一個即可
new AnnotationConfigApplicationContext(AppConfig.class);
@Configuration導入xml配置
@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
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();
}
}
}
@Lazy懶加載
可以與@Configuration和@Bean配合使用。Spring默認不是懶加載。
@EnableXXX注解
配合@Configuration使用,包括 @EnableAsync, @EnableScheduling, @EnableTransactionManagement, @EnableAspectJAutoProxy, @EnableWebMvc。
@EnableWebMvc
常見使用方式如下所示:
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyWebConfiguration {
}
一旦使用了該注解,則會默認加載WebMvcConfigurationSupport配置,包括:
1. HandlerMappings
1. RequestMappingHandlerMapping 用於處理url到注解controller的method映射,序號是0
2. HandlerMapping 用於處理url到view的映射,序號是1
3. BeanNameUrlHandlerMapping 用於處理url到controller的beanname映射,序號是2
4. HandlerMapping 用於處理靜態資源,序號是Integer.MAX_VALUE-1
5. HandlerMapping 用於forward到default servlet,序號是Integer.MAX_VALUE
2. HandlerAdapters
1. RequestMappingHandlerAdapter 用於處理帶有注解Controller的響應處理方法
2. HttpRequestHandlerAdapter 用於處理實現 HttpRequestHandler 的響應處理器
3. SimpleControllerHandlerAdapter 用於處理實現Controller接口的響應處理器
3. HandlerExceptionResolverComposite
1. ExceptionHandlerExceptionResolver 用於處理@ExceptionHandler注解
2. ResponseStatusExceptionResolver 用於處理@ResponseStatus注解
3. DefaultHandlerExceptionResolver 用於處理已知的Spring異常
4. AntPathMatcher 和 UrlPathHelper
你也可以不使用該注解,而是配置類繼承WebMvcConfigurationSupport類或DelegatingWebMvcConfiguration,。或者使用@EnableWebMvc,並實現 WebMvcConfigurer接口,或 WebMvcConfigurerAdapter 適配器,例如:
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addConverter(new MyConverter());
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MyHttpMessageConverter());
}
// More overridden methods ...
}
@Profile邏輯組配置
用於指定配置類加載的邏輯組(a named logical grouping),只有在組內的配置類才會被加載。該注解類似於在xml的配置,例如\。@Profile可以在配置類上,也可以在配置類的方法上。如果不配置該注解,默認是無論如何都會加載。
可以通過以下方式設置:
在JVM參數、系統環境參數或web.xml的initParam spring.profiles.active、spring.profiles.default(來自org.springframework.core.env.AbstractEnvironment) 。如果當spring.profiles.active屬性被設置時,那么Spring會優先使用該屬性對應值來激活Profile。當spring.profiles.active沒有被設置時,那么Spring會根據spring.profiles.default屬性的對應值來進行Profile進行激活。如果上面的兩個屬性都沒有被設置,那么就不會有任務Profile被激活,只有定義在Profile之外的Bean才會被創建。
或者使用ConfigurableEnvironment.setActiveProfiles 指定需要激活的邏輯組名。
在測試類中,使用@ActiveProfiles注解指定。
@Profile("embedded", "!abc")//表示當embedded激活,abc不激活時加載本配置類
@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
}
}
等同於
<beans profile="development">
<!-- 只掃描開發環境下使用的類 -->
<context:component-scan base-package="" />
<!-- 加載開發使用的配置文件 -->
<util:properties id="config" location="classpath:dev/config.properties"/>
</beans>
我們甚至可以自定義Profile注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("dev")
pubilc @interface Dev {
}
ConfigurableEnvironment
用於在沒有配置項的時候,用硬編碼方式指定激活邏輯組、設置默認邏輯組,或增加新的邏輯組等。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("dev");
ctx.register(TransferServiceConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
ctx.refresh();
配置信息
最主要需要搞懂三個類PropertySource、PropertyResolver、Environment,PropertySource用於定於基本的配置數據來源,PropertyResolver用於對PropertySource進行解析,包括EL表達式(占位符替換),或進行類型轉換(String->Integer等),Environment繼承自PropertyResolver,這也是為何使用Environment.getProperty可以用el表達式的原因。
propertySource
propertySource
propertyResolver
propertyResolver
Environment
Environment
被使用
繼承
PropertySource
加載各種配置信息。其中ComposePropertySource提供了組合PropertySource的功能,查找順序就是注冊順序。默認提供了一個MutablePropertySources實現,我們可以調用addFirst添加到列表的開頭,addLast添加到末尾,另外可以通過addBefore(propertySourceName, propertySource)或addAfter(propertySourceName, propertySource)添加到某個propertySource前面/后面;最后大家可以通過iterator迭代它,然后按照順序獲取屬性。
Map<String, Object> map = new HashMap<>();
map.put("encoding", "gbk");
PropertySource propertySource1 = new MapPropertySource("map", map);
System.out.println(propertySource1.getProperty("encoding"));
ResourcePropertySource propertySource2 = new ResourcePropertySource("resource", "classpath:resources.properties"); //name, location
System.out.println(propertySource2.getProperty("encoding"));
PropertyResolver 與 Environment
Environment環境,比如JDK環境,Servlet環境,Spring環境等等;每個環境都有自己的配置數據,如System.getProperties()、System.getenv()等可以拿到JDK環境數據;ServletContext.getInitParameter()可以拿到Servlet環境配置數據等等;也就是說Spring抽象了一個Environment來表示環境配置。也可以獲取或設置Profile。
MockEnvironment:模擬的環境,用於測試時使用;
StandardEnvironment:標准環境,普通Java應用時使用,會自動注冊System.getProperties() 和 System.getenv()到環境;
StandardServletEnvironment:標准Servlet環境,其繼承了StandardEnvironment,Web應用時使用,除了StandardEnvironment外,會自動注冊ServletConfig(DispatcherServlet)、ServletContext及JNDI實例到環境;