Spring in Action读书笔记之根据条件装配bean

209 阅读2分钟

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

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

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

@Configuration
@PropertySource("classpath:site.properties")
public class MagicConfig {

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

}

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

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,不需要有值):

magic=

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

@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如下:

@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如下:

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”或扫描下方二维码关注微信公众号,第一时间获取最新文章(^_^)

谈谈IT