条件化的Bean——@Conditional注解

来源:互联网 发布:公司屏蔽了淘宝怎么办 编辑:程序博客网 时间:2024/06/04 18:22

条件化的Bean——@Conditional注解

当我们希望某个Bean满足了一定的条件才会被创建的时候,我们就可以使用@Conditional注解(Spring 4引入)来实现这种功能。该注解可以用到带有@Bean注解的方法上,如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean会被忽略。

常见条件注解

  1. @ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
  2. @ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
  3. @ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
  4. @ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
  5. @ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
  6. @ConditionalOnNotWebApplication(不是web应用)

自定义条件

假设有一个名为MagicBean的类,我们希望只有设置了magic环境属性的时候,Spring才会实例化这个类。

条件化地配置bean

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

检查是否存在magic属性

package com.zheng.spring;import org.springframework.context.annotation.Condition;import org.springframework.context.annotation.ConditionContext;import org.springframework.core.env.Environment;import org.springframework.core.type.AnnotatedTypeMetadata;public class MagicExistsCondition implements Condition {    @Override    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {        Environment env = conditionContext.getEnvironment();        return env.containsProperty("magic"); // 检查magic属性    }}

matches()方法通过给定的ConditionContext对象进而得到Environment对象,并使这个对象检查环境中是否存在名为magic的环境属性。

其中ConditionContext是一个接口

public interface ConditionContext {    BeanDefinitionRegistry getRegistry();    ConfigurableListableBeanFactory getBeanFactory();    Environment getEnvironment();    ResourceLoader getResourceLoader();    ClassLoader getClassLoader();}
  • 借助getRegistry()返回的BeanDefinitionRegistry检查bean定义;
  • 借助getBeanFactory()返回的ConfigurableListableBeanFactory检查bean是否存在,甚至探查bean的属性;
  • 借助getEnvironment()返回的Environment检查环境变量是否存在以及它的值是什么;
  • 读取并探查getResourceLoader()返回的ResourceLoader所加载的资源;
  • 借助getClassLoader()返回的ClassLoader加载并检查类是否存在。

AnnotatedTypeMetadata则能够让我们检查带有@Bean注解的方法上还有什么其他的注解。像ConditionContext一样,AnnotatedTypeMetadata也是一个接口。

public interface AnnotatedTypeMetadata {    boolean isAnnotated(String var1);    Map<String, Object> getAnnotationAttributes(String var1);    Map<String, Object> getAnnotationAttributes(String var1, boolean var2);    MultiValueMap<String, Object> getAllAnnotationAttributes(String var1);    MultiValueMap<String, Object> getAllAnnotationAttributes(String var1, boolean var2);}

借助isAnnotated()方法,我们能够判断带有@Bean注解的方法是不是还有其他特定的注解。借助其他的那些方法,我们能够检查@Bean注解的方法上其他注解的属性。

@Profile注解与条件化的关系

从Spring 4开始,@Profile注解基于@Conditional和Condition实现。

下面是@Profile实现的源码

@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();}

其中ProfileCondition检查某个bean profile是否可用,源码如下

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;    }}

ProfileCondition通过AnnotatedTypeMetadata得到了用于@Profile注解的所有属性。借助该信息,它会明确地检查value属性,该属性包含了bean的profile名称。然后,它根据通过ConditionContext得到的Environment来检查[借助acceptsProfiles()方法]该profile是否处于激活状态。如果是则选择这个profile bean进行创建。

阅读全文
0 0