Spring扩展------基于`@Conditional`注解以及`Condition`接口的扩展

@Conditional注解是spring在4.0版本提供的一个注解,作用是贴有这个注解或间接贴有的bean在满足指定的Condition接口实现类的matches方法校验之后,才注册这个bean。关于@Conditional注解的实现原理,可以看看前面写的一篇文章。@Conditional注解的解析。

1. 直接使用@Conditional注解

1.1 定义一个Bean,并在上面贴上@Conditional注解
public class ConditionalTestBootstrap {
    @Bean
    @Conditional(MyCondition.class)
    public String conditionTest(){
        return "condition test";
    }   
}

 如上面的代码所示,直接使用@Conditional注解的方式。使用这个注解的前提要求是:这个对象需要是一个被容器管理的对象。

1.2 @Conditional注解指定的类实现Condition接口

 上面的@Conditional注解中指定的类是MyCondition。因此这个类需要实现Condition接口

public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Map attributes = annotatedTypeMetadata.getAnnotationAttributes(Conditional.class.getName());
        Object value = attributes.get("value");
        if (value!=null){
            System.out.println("当校验条件为true的时候,返回true");
            return true;
        }else {
            System.out.println("当校验条件为false的时候,返回false");
            return false;
        }
    }
}

 在实现的matches方法中,可以自行定义判断逻辑,从AnnotatedTypeMetadata中可以获取贴有注解信息的对象或者方法的很多信息,可以利用这些信息来进行逻辑判断。
 当最终结果返回为true的时候,就表示校验符合,就会将bean进行注册。

1.3 在启动类中进行校验
public class ConditionalTestBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(ConditionalTestBootstrap .class)
                .web(WebApplicationType.NONE)
                .run(args);
        String conditionTest = applicationContext.getBean("conditionTest", String.class);
        System.out.println("conditionTest Bean "+conditionTest);
        //关闭上下文
        applicationContext.close();
    }
}

 最终的运行结果为conditionTest Bean condition test。此时说明这个bean成功的被注入到了容器之中。
 当我们把上面实现的matches方法中返回的结果改为false的时候再试试

public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
       return false;
    }
}

此时运行结果为

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'conditionTest' available
    at 
    ......

 最后运行出错了,因为容器中没有名称为conditionTest的bean

2. 间接使用@Conditional注解

 因为spring原生提供的@Conditional注解内部只有一个value属性用来指定我们匹配规则的类,没有其余的属性供我们使用。所以通常都是对@Conditional注解进行派生使用。

2.1 定义一个@Conditional注解的派生注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
    /**
     * java 系统属性名称
     * @return
     */
    String name() default "";

    /**
     * java系统属性值
     * @return
     */
    String value() default "";
}

 定义@Conditional的派生注解,通常是在自定义的注解上加上一个@Conditional注解并指定实现匹配规则的Condition接口的实现类。

2.2 实现Condition接口处理
public class OnSystemPropertyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map attributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
        String propertyName = String.valueOf(attributes.get("name"));
        String propertyValue = String.valueOf(attributes.get("value"));
        String javaProperty = System.getProperty(propertyName);
        return propertyValue.equals(javaProperty);
    }
}

 上面就是自定义的判定逻辑。从AnnotatedTypeMetadata中获取ConditionalOnSystemProperty类型的注解,然后获取到注解内的属性值。然后比较来决定匹配结果。

2.3 在bean上面使用自定义的注解
public class ConditionalOnSystemPropertyBootstrap {
    @Bean
    @ConditionalOnSystemProperty(name = "user.name",value = "Administrator")
    public String helloWorld(){
        return "hello world szh";
    }
}

 在定义的bean上面加上自定义的@ConditionalOnSystemProperty注解,并添加上对应的条件。

2.4 在启动类中校验
public class ConditionalOnSystemPropertyBootstrap {
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(ConditionalOnSystemPropertyBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        String helloWorld = applicationContext.getBean("helloWorld", String.class);
        System.out.println("helloWorld Bean "+helloWorld);
        //关闭上下文
        applicationContext.close();
    }
}

 最后的运行结果为helloWorld Bean hello world szh。说明我们的bean成功的注入到了容器中。到这里@Conditional注解以及Condition接口的扩展就完了。

你可能感兴趣的:(Spring扩展------基于`@Conditional`注解以及`Condition`接口的扩展)