一、Spring profile
使用spring profile可以根据环境创建bean
1. 配置
java配置
@Profile("dev")
Spring3.1只能使用在类级别上,Spring 3.2开始可以使用在方法级别上,与@bean一同使用。
xml配置
<beans profile="dev">
...
</beans>
2. 激活
Spring在确定那个profile处于激活状态时,需要依赖两个独立属性,spring.profiles.active
,spring.profiles.default
。设置了spring.profiles.active
属性,激活该属性值,否则激活spring.profiles.default
,都没有设置则都不会激活。
激活方式:
- 作为DispatherServlet的初始化参数
- 作为Web应用的上下文参数
- 作为JNDI条目
- 作为环境变量
- 作为JVM的系统属性
- 在集成测试类上,使用
@ActiveProfiles
注解
Example:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring.xml</param-value>
</context-param>
<!-- 为上下文设置的默认的profile -->
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>location</param-value>
</init-param>
<!-- 为Servlet设置的默认的profile -->
<init-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</servlet>
</web-app>
Test.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { RootConfig.class })
@ActiveProfiles("dev")
public class UserTest {}
二、条件化的bean
在满足特定需求的情况下才创建bean
@Conditional(Class.class)
注解标注的bean
Class类可以是任意实现了Condition接口的类型 。
三、处理自动装配的歧义性
1. 设置首选的bean,只适用于一个首选bean
@Primary
<bean id="" class="" primary="true">
2. 限定自动装配的bean
@Qualifier("限定符")
与 @Autowired , @Inject协同使用,在注入的时候指定要注入哪个bean。
- 限定符可以是最简单的bean id,为了防止重构代码,改变类名,默认的bean id发生改变,可以自定义限定符
- 创建自定义的限定符:在bean声明上添加
@Qualifier("")
注解 - 使用自定义限定符注解
四、 bean的作用域
默认情况下,Spring应用上下文中的所有bean都是以单例形式创建的。
Spring定义的多种作用域,可以基于这些作用域创建bean:
- 单例 (Singleton)
- 原型 (Prototype) : 每次注入或者通过spring应用上下文获取的时候都会创建一个新的实例。
- 会话(Session):在Web应用中,每个会话创建一个实例。
- 请求(Request):在Web应用中,每个请求创建一个实例。
改变默认作用域使用@Scope
注解,可以与 @Component 或者 @Bean一起使用。
使用会话和请求作用域
注解方式:
会话作用域的bean注入到单例作用域,由于会话作用域在用户进入系统时才会创建,而单例是在应用上下文加载的时候创建,而且会话作用域需要是特定用户的实例注入。Spring会将一个代理注入,使用@Scope
的proxyMode
属性设置代理模式,如果是接口@Scope( value = WebApplicationContext.SCOPE_SESSION proxyMode=ScopedProxyMode.INTERFACES)
,如果是类,需要使用CGLib生成基于类的代理proxyMode=ScopedProxyMode.TARGET_CLASS
。请求作用域同样以代理方式注入。
XML配置
使用xml配置声明会话或者请求作用域的bean,使用<bean>
元素的scope
属性只能设置bean的作用域,设置代理模式需要使用Spring aop 命名空间的一个新元素<aop:scoped-proxy />
:
<bean id="" class="" scope="session">
<aop:scoped-proxy />
</bean>
默认使用CGLib创建目标类的代理,设置<aop:scoped-proxy proxy-target-class="fasle" />
,使其生成基于接口i的代理。
五、运行时值注入
Spring提供了两种在运行时求值的方式:
- 属性占位符(Property palceholder)
- Spring表达式语言(SpEL)
1、注入外部值
Spring中的Environment
:
通过@PropertySource(value = { "classpath:/properties/db.properties" })
,这个属性文件会加载到Spring的Environment中,可以从这里检索属性,例如:
@PropertySource(value = { "classpath:/properties/db.properties" })
public class Test {
@Autowired
private Environment env;
public void envTest() {
String url = env.getProperty("jdbc.url");
System.out.println(url);
}
}
其他的一些方法:
String[] getActiveProfiles();
String[] getDefaultProfiles();
boolean containsProperty(String key);
··· ···
解析属性占位符
xml : ${jdbc.driver}
java:@Value("${jdbc.driver}")
使用占位符需要配置属性源,可以通过配置PropertySourcesPlaceholderConfigurer
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer();
return placeholderConfigurer;
}
xml配置:
<context:property-placeholder/>
解析外部属性能将值的处理推迟到运行时,但是只能根据名称解析属性源的属性。
2、使用Spring表达式语言进行装配
SpEL可以将在运行时计算得到的值装配到bean,SpEL有很多特性,包括:
- 使用bean的id引用bean
- 调用方法和访问对象的属性
- 对值进行算术、关系和逻辑运算
- 正则表达式匹配
- 集合操作
SpEL还能用于依赖注入以外的其他地方。
SpELl样例:
SpEL需要放到#{···}
中
#{1}
//T() 表达式会将System视为Java中对应的类型,调用其静态方法
#{T(System).currentTimeMillis()}
//引用其他bean或bean的属性
#{beanId.beanProperty}
//通过systemProperties对象引用系统属性
#{systemProperties['jdbc.url']}
//SpEL运算符
#{2 * T(java.lang.Math).PI * circle.radius}
//集合计算
#{musicBox.songs[4].title}
#{'This is a test'[3]}
··· ···