0%

高级装配

环境与profile

Profile注解

单独使用时: 作用于类名,指定该类属于哪一个profile环境
@bean一起: 作用于方法,指定该bean属于哪一个profile环境

激活profile

设置 属性 spring.profiles.active。

  • 作为DispatcherServlet的初始化参数;
  • 作为Web应用的上下文参数;
  • 作为JNDI条目;
  • 作为环境变量;
  • 作为JVM的系统属性;
  • 在集成测试类上,使用@ActiveProfiles注解设置。

条件化bean

@Conditional 注解: 作用于类名上,与 Condition接口 配合。
Condition 接口: 只有一个 matches方法,只有在该方法返回 true 时才会创建带有@Conditional的bean。

通过这两个注解和接口的配合,可以下面措施来决定是否创建 被注解的bean。

  • 检查环境变量是否存在指定的值
  • 检查指定的bean是否存在
  • 检查指定的资源是否存在
  • 等等

样例 Profile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

/**
* The set of profiles for which the annotated component should be registered.
*/
String[] value();

}


class ProfileCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() != null) {
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
return true;
}
}
return false;
}
}
return true;
}

}

##自动装配歧义性

  • @Primary, 与@bean或者@Component组合: 将有该注解的bean设为首选项
  • @Qualifier, 与@Autowired组合: 指定注入哪个bean
  • @Qualifier, 与@Component@Bean组合: 指定该bean生产的beanId

##bean的作用域

@Scope注解 与@Component@Bean组合,表明bean的作用域。

其有以下四种值:

  • 单例(Singleton):在整个应用中,只创建bean的一个实例。
  • 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
  • 会话(Session):在Web应用中,为每个会话创建一个bean实例。 使用场景: 购物车等
  • 请求(Rquest):在Web应用中,为每个请求创建一个bean实例。

请求域和会话域的详细介绍 参见《spring实战》章节3.4.1 。

运行时值注入

引入外部值

  1. Value注解: 可以使用 属性占位符或者SpEL表达式。
  2. Environment 对象: 获取环境变量和判断运行profile
1
2
3
4
5
6
7
8
9
public class Ad{

@Value("${a.c.v}")
private String aaa;

@Autowired
Environment environment;

}

SpEL

  • 使用bean的ID来引用bean;
  • 调用方法和访问对象的属性;
  • 对值进行算术、关系和逻辑运算;
  • 正则表达式匹配;
  • 集合操作。

属性占位符需要放到 “${ … }”之中
SpEL表达式需要放到 “#{ … }”中

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 调用普通类的方法
#{T{System}.currentTimeMillis()}

-- 获取 指定bean的字段信息
#{beanId.field}

-- 调用 指定bean的方法
#{beanId.method()}

-- 引用系统属性
#{systemProperties['aa.aa']}

-- 避免空指针,中间过程出现null,表达式结果返回null
#{beanId.select()?.dosome()}