Advanced Wiring-高级装配
Spring所有的高级features都可以在Spring官网具体的Project的Reference文档和API中进行查看。
1.Profile-环境切换
Background:项目在不同的环境,开发、测试、生产等需要连接不同的DateSource。其中一种方式是在配置类或XML文件中配置,在构建阶段(如Maven或Gradle)确定将哪个配置编译到部署应用中,但其问题是需要为每种环境重新构建应用。
Definition profile:Spring profile是在运行时而不是在构建是确定创建具体bean。在Class-level或Method-level上添加@Profile("env")
or <Beans profile="env">
,所有的配置文件都会放到部署单元之中(e.g, war file), 但只有profile属性与当前激活profile相匹配的配置文件才会被用到。
Active profile:优先创建 spring.profiles.active 属性的bean,其次创建spring.profiles.default属性的。如果均没有设置,只会创建没有定义在profile中的bean。有多种方式来设置这两个属性:
- As initialization parameters on DispatcherServlet
- As context parameters of a web application
- As JNDI entries
- As environment variables
- As JVM system properties
- Using the @ActiveProfiles annotation on an integration test class
2.Conditional beans-条件化bean
Background:类似定时任务或图形界面编程,你希望在某个事件发生后才创建某个特定的bean,或希望这个bean在另外一个bean生命创建后才进行创建。
Spring 4 之后引入了@Conditional
annotation, if conditonal ? create : ignore
@Configuration
public class MagicConfig {
@Bean
@Conditional(MagicExistsCondition.class)
public MagicBean magicBean() {
return new MagicBean();
}
}
public class MagicExistsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("magic");
}
}
设置给@Conditional
的类必须实现 Condition接口,@Conditional
通过Condition接口进行条件对比。
3.Addressing ambiguity in autowiring-处理自动装配歧义
Background:在进行自动装配过程中有多个bean被匹配到的话,Spring会失败并抛NoUniqueBeanDefinitionException异常。
3.1 使用@Primary
标识首选bean,但有多个首选bean时会带来新的歧义性。
3.2 使用限定符@Qualifier
,能够在可选bean上进行缩小范围的操作(recommend)
4.Scope-bean的作用域
Backgroud:Default,Spring应用上下文中所有的bean都是单例的singleton。但有些类是易变的(mutable),或需要多个会话需求,因此重用是不安全的。
Spring defines several scopes:
- Singleton —One instance of the bean is created for the entire application.
- Prototype —One instance of the bean is created every time the bean is injected into or retrieved from the Spring application context.
- Session —In a web application, one instance of the bean is created for each session.
- Request —In a web application, one instance of the bean is created for each request.
4.1 程序使用@Scope("prototype")
或<bean id="" class="" scope="prototype" />
来表明原型作用域。
4.2 会话和请求作用域。以每个用户都有自己的一个购物车为例:
@Component @Scope( value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES/ScopedProxyMode.TARGET_CLASS) public ShoppingCart cart() { ... }
这会告诉Spring为Web应用中每个会话创建一个ShoppingCart ,这会创建多个bean实例,但对于特定会话只会创建一个实例,在当前会话相关操作中,这个bean相当于单例。
proxyMode属性解决了将session或request scope 的bean不能直接注入到singleton bean中的问题。Spring会把bean注入到对于的proxy代理中,当service调用bean时,代理会对其进行懒解析并将调用委托给会话作用域内真正的bean。
在XML中声明作用域代理<aop:scoped-proxy proxy-target-class="false/true" />
5. Runtime value injection-运行时注入
Background:avoid hard-coded values and let the values be determined at runtime 。
Spring offers two ways of evaluating values at runtime:
- Property placeholders-属性占位符
使用”${…}” - The Spring Expression Language (SpEL)-Spring表达式(推荐)
使用”#{SEL}”
Spring Expression Language (SpEL)
- 引用bean、属性和方法。
e.g,#{beanID.attribute}
or#{beanID.method()}
- 访问Java类的静态方法和常量。
e.g,T(java.lang.Math).PI
- 使用运算符。
算术 :+、%、^
比较:<、lt
逻辑:or |
条件:? : (ternary)
正则:matches - 集合和数组
#{arrays[index].porperty}
查询运算符#{arrays .?[condition]}、第一个匹配”.^[]”、最后一个匹配”.$[]”
投影运算符”.![]”,从集合成员中选择特定属性放到另一个集合中