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