Spring in Action 读书笔记之根据条件创建 bean

字数783 大约花费4分钟

有时候希望只在某些情况下才创建 bean,Spring4 引入的 @Conditional 标签可以做到这一点。

Spring in Action(Spring 实战)的第三章第二节(3.2 Conditional beans)讲述了如何根据条件创建 bean,以下是我阅读这一节的读书笔记。

以下使用显示创建 bean 的方法,举例说明如何根据条件创建 bean(创建 bean 的方法)。

1
2
3
4
5
6
7
8
9
10
11
@Configuration
@PropertySource("classpath:site.properties")
public class MagicConfig {

@Bean
@Conditional(MagicExistsCondition.class)
public MagicBean magicBean() {
return new MagicBean();
}

}

magicBean()加了 @Conditional 标签,并且指定 MagicExistsCondition 定义判断逻辑。

1
2
3
4
5
6
7
8
9
public class MagicExistsCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("magic");
}

}

MagicExistsCondition 的 matches 方法,决定是否加载 bean。当返回值为 true 时加载,否则不加载。这段代码表示,判断环境中是否定义了 magic 属性。我在 MagicConfig 方法上加了 @PropertySource 标签,用来指定配置文件为 classpath 下的 site.properties,并且在文件中写入以下属性(这个例子中只需要有 key,不需要有值):

1
magic=

这样,MagicExistsCondition 的 matches 方法就会返回 true,从而容器会创建 magicBean()对应的 bean 了。以下测试程序用来验证 context 中是否包含 magicBean。验证通过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=MagicConfig.class)
public class MagicExistsTest {

@Autowired
private ApplicationContext context;

/*
* This test will fail until you set a "magic" property.
* You can set this property as an environment variable, a JVM system property, by adding a @BeforeClass
* method and calling System.setProperty() or one of several other options.
*/

@Test
public void shouldNotBeNull() {
assertTrue(context.containsBean("magicBean"));
}

}

还记得 上一节 讨论的根据开发环境装配 bean 吗,配置文件中的 @Profile 标签本身是被 @Conditional 标注,并且指定 ProfileCondition 进行判断的,这是 Spring 实现的 @Conditional 标签的特例,而本节可以看到,我们可以根据需要
自己决定在什么情况下加载 bean。

Profile 如下:

1
2
3
4
5
6
7
8
9
10
11
12
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

/**
* The set of profiles for which the annotated component should be registered.
*/

String[] value();

}

ProfileCondition 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}

}

随书提供的官方样例(点击从 官方网站下载),没有添加属性文件,也没有在 MagicConfig 中加载属性,所以测试用例是跑不通的,作者把这部分实现工作留给了读者。所以我在 resource 目录下(项目的 classpath)增加了上文中的 site.properties 文件,并且将用 PropertySource 标注,指明从 classpath:site.properties 加载属性,这样操作之后,测试用例通过了。当然,您也可以用自己的方式加载属性。

谈谈 IT的文章均为原创或翻译(翻译会注明外文来源),转载请以链接形式标明本文地址: http://tantanit.com/springinaction-du-shu-bi-ji-zhi-gen-ju-tiao-jian-zhuang-pei-bean/

谈谈IT

欢迎关注官方微信公众号获取最新原创文章