SpringBoot高级-自动配置原理剖析二

前言:根据剖析一,继续拓展自动配置原理

新需求:将类的判断定义为动态的,判断哪个字节码文件存在可以动态指定。下面是具体的步骤。

1、新建一个自定义注解 ConditionOnClass ,顺带解释下注解的作用:
@Target:注解可以作用的范围(类、方法、属性等)。
@Retention:注解生效的时机。
@Documented:可生成文档注释。
@Conditional:是Spring5提供的条件注解,详细说明和使用见剖析一。

/**
 * @description:自定义条件注解
 * @date: 2020/10/9 17:52
 * @author: winson
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {

    //可接收参数数组
    String[] value();

}

2、修改自定义User配置类,使用自定义注解

/**
 * @description:User配置类
 * @date: 2020/10/9 15:25
 * @author: winson
 */
@Configuration
public class UserConfig {

    @ConditionOnClass("redis.clients.jedis.Jedis")
    @Bean
    public User user() {
        return new User();
    }
}

3、修改条件类

/**
 * @description:条件类
 * @date: 2020/10/9 16:24
 * @author: winson
 */
public class ClassCondition implements Condition {
    /**
     *
     * @param context 上下文对象,可以获取环境、IOC容器、ClassLoader对象
     * @param metadata 注解元对象,可以用于获取注解定义的属性值
     * @return
     */
    //2、需求:导入通过注解属性值value指定坐标后创建Bean
    //思路:获取注解属性值 value
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        boolean flag = true;
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        System.out.println(annotationAttributes);
        return flag;
    }
}

4、启动程序,测试结果,发现通过注解原对象,获取的annotationAttributes的打印结果,Key为Value,即自定义注解@ConditionOnClass的属性名,Value为自定义注解使用时所赋的值redis.clients.jedis.Jedis。能获取到user的Bean对象,因为我在pom.xml中导入了Jedis的依赖,也证明了我们自定义的注解没有问题,可以生效。

5、我们再将ClassCondition类修改一下,如果IOC中含有所指定的字节码文件,就返回true,让user的Bean注入到IOC容器中。

    //2、需求:导入通过注解属性值value指定坐标后创建Bean
    //思路:获取注解属性值 value
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        boolean flag = true;
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        String[] values = (String[]) annotationAttributes.get("value");
        try {
            for (String value : values) {
                Class<?> cls = Class.forName(value);
            }
        } catch (ClassNotFoundException e) {
            flag = false;
        }
        return flag;
    }

6、测试结果

6.1、将Jedis依赖注释掉,再启动程序,不会再从IOC容器中获取到user的Bean了。

6.2、我们将自动注解想获取的文件故意写错,Jedis依赖依旧添加,测试结果

故意将参数(redis.clients.jedis.Jedis.false)写错,再测试

@Configuration
public class UserConfig {

    @ConditionOnClass("redis.clients.jedis.Jedis.false")
    @Bean
    public User user() {
        return new User();
    }

}

发现结果也不会获取到user的Bean

小结:该案例实现一个需求,用户想要自动注入user的Bean,必须添加指定的依赖,至于什么依赖,用户自己指定。

posted @ 2020-10-09 18:32  温森  阅读(223)  评论(0编辑  收藏  举报