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