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

有时候希望只在某些情况下才创建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加载属性,这样操作之后,测试用例通过了。当然,您也可以用自己的方式加载属性。

© 2022 谈谈IT All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero