SpringBoot2.0深度实践学习笔记(三)之 条件装配

基于编程方式实现条件装配Spring Boot 自动装配
@Profile是3.1提出来的,但在4.0 发生了变化---通过注解调解

查看源码来看一下:
@Profile标注了@Conditional(ProfileCondition.class)

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)//profile在4.0 发生了变化---通过ProfileCondition实现的
public @interface Profile {

   /**
    * The set of profiles for which the annotated component should be registered.
    */
   String[] value();

}

ProfileCondition类,实现了Condition接口

ass ProfileCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        MultiValueMap attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
        if (attrs != null) {
            for (Object value : attrs.get("value")) {
                if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
                    return true;
                }
            }
            return false;
        }
        return true;
    }

}

Condition接口,是通过上下文,元数据类型的注解,来查看是否匹配,条件是否满足
注意:AnnotatedTypeMetadata接口--元信息,保留一些关于标注的信息,就是下面提到的一些属性方法等

@FunctionalInterface
public interface Condition {

   /**
    * Determine if the condition matches.
    * @param context the condition context
    * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
    * or {@link org.springframework.core.type.MethodMetadata method} being checked
    * @return {@code true} if the condition matches and the component can be registered,
    * or {@code false} to veto the annotated component's registration
    */
   boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

再来看一个:SpringBoot的ConditionalOnProperty注解
观察到,这个注解也是标注了一个@Conditional({OnPropertyCondition.class}),OnPropertyCondition这个类最终也是实现的Condition接口

1、
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({OnPropertyCondition.class})
public @interface ConditionalOnProperty {
    String[] value() default {};

    String prefix() default "";

    String[] name() default {};

    String havingValue() default "";

    boolean matchIfMissing() default false;
}

2、
@Order(Ordered.HIGHEST_PRECEDENCE + 40)
class OnPropertyCondition extends SpringBootCondition {...}

3、
public abstract class SpringBootCondition implements Condition {...}  

参照以上的源码实现一个小栗子,基于编程方式实现 - @ConditionalOnSystemProperty
【小栗子】
按照源码的提示,新建一个condition包名
1、新建一个注解ConditionalOnSystemProperty,定义属性方法

/**
 *  java系统属性  条件判断*
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
    /**
     * Java 系统属性名称
     * @return
     */
    String name();

    /**
     * Java 系统属性值
     * @return
     */
    String value();
}

2、实现OnSystemPropertyCondition
参照:OnPropertyCondition类继承SpringBootCondition ,
SpringBootCondition 是一个抽象的实现,最终还是实现Condition,所以这里就直接实现Condition接口
采用哪个都可以SpringBootCondition或者Condition都可以。

/**
 * 系统属性条件判断
 */
public class OnSystemPropertyCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        Map attributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
        //获取name,value
        String propertyName = String.valueOf(attributes.get("name"));

        String propertyValue = String.valueOf(attributes.get("value"));

        //取到的值是不是和系统里的相匹配
        String javaPropertyValue = System.getProperty(propertyName);

        return propertyValue.equals(javaPropertyValue);
    }
}

说明:
有很多获取metadata的方式,这里采用
getAnnotationAttributes(),返回值是Map,是指检索给定类型注解的属性
在这里也就是检索ConditionalOnSystemProperty里定义的是name和value的属性方法

3、创建引导类
bootstrap包下,新建引导类ConditionOnSystemPropertyBootstrap
引导类启动的时候@ConditionalOnSystemProperty注解会被激活

/**
 * 系统属性条件引导类
 */

public class ConditionOnSystemPropertyBootstrap {

    //定义一个bean:helloWorld
    @Bean
    @ConditionalOnSystemProperty(name = "user.name",value = "Lenovo")//进行条件装配,和系统的名字一样的话,就导入进来
    public String helloWorld() {
        return "Hello,World PK";
    }
   

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(ConditionOnSystemPropertyBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);


        // 条件满足的话,通过名称和类型获取 helloWorld Bean,不满足无法获取
        String helloWorld = context.getBean("helloWorld", String.class);

        System.out.println("helloWorld Bean : " + helloWorld);
        //关闭上下文
        context.close();
    }
}

4、运行引导类
value的值和系统的名称相匹配,条件是满足的,返回了Hello,World PK


Image 3.png

条件不满足的时候,会报错,bean找不到


Image 4.png

你可能感兴趣的:(SpringBoot2.0深度实践学习笔记(三)之 条件装配)