Spring@Conditional详解
Posted 幽灵雾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring@Conditional详解相关的知识,希望对你有一定的参考价值。
【功能介绍】
@Conditional
给想要注入Bean增加限制条件,只有满足限制条件才会被构造并注入到Spring的IOC容器中,通常和@Bean注解一起使用。
【使用实例】
Bean类,以及注入Bean的类:
@Component
public class TestConfig
@Bean
// 注入Bean之前增加限制条件:MyCondition,条件满足才会构造TestBean同时注入
@Conditional(MyCondition.class)
public TestBean testbean()
System.out.println("=====run new TestBean");
TestBean testBean = new TestBean();
testBean.setId(1L);
return testBean;
public class TestBean
private Long id;
public Long getId()
return id;
public void setId(Long id)
this.id = id;
@Override
public String toString()
return "TestBean" +
"id=" + id +
'';
自定义条件类:
public class MyCondition implements Condition
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
//context能够获取到IOC相关的信息、对象
//获取ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取类加载器
ClassLoader classLoader = context.getClassLoader();
//获取当前环境信息
Environment environment = context.getEnvironment();
//获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
//metadata能取到注解的元信息
metadata.getAnnotations().forEach(a ->
//注解的class
Class<Annotation> type = a.getType();
//注解对应的attribute
Object value = a.getValue("value").get();
);
//返回false表示未满足条件,不进行构造和注入;返回true表示满足条件,正常构造和注入
return false;
测试类:
@SpringBootTest
class MyConsul1ApplicationTests
//required=false:表示如果testBean在容器中不存在,也不会异常中断,而是单纯的testBean=null而已
@Autowired(required=false)
private TestBean testBean;
@Test
public void test()
System.out.println("testBean = " + testBean);
输出结果:
//如果MyCondition中返回true,则输出正常:
testBean = TestBeanid=1
//如果MyCondition中返回false,则输出null:
testBean = null
【源码分析】
从启动开始,选取和@Conditional有关的源码:
第一步,SpringBoot启动,并初始化applicationContext
SpringApplication.run
->
SpringApplication.createApplicationContext
->
applicationContext = new AnnotationConfigServletWebServerApplicationContext
->
applicationContext.reader = new AnnotatedBeanDefinitionReader
->
applicationContext.reader. conditionEvaluator = new ConditionEvaluator
这一步,主要是初始化applicationContext,其中包括:
用来进行注解Bean解析的reader处理器(AnnotatedBeanDefinitionReader),以及reader中的条件处理器(conditionEvaluator),如图:
第二步,applicationContext预处理
SpringApplication.prepareContext
->
SpringApplication.load
->
SpringApplication.createBeanDefinitionLoader
->
BeanDefinitionLoader.load
->
AnnotatedBeanDefinitionReader.register -> registerBean -> doRegisterBean
->
conditionEvaluator.shouldSkip
->
BeanDefinitionReaderUtils.registerBeanDefinition
->
registry.registerBeanDefinition
这一步,主要是要进行Bean的构造及注册,其中conditionEvaluator.shouldSkip决定了是否执行后续的Bean构造及注册,如图:
第三步,条件逻辑处理
这里是@Conditional注解的核心处理过程,主要就是通过回调我们自定义的Condition.matches方法来实现:
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase)
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName()))
return false;
//判断是:PARSE_CONFIGURATION还是REGISTER_BEAN
//PARSE_CONFIGURATION:代表解析配置类阶段,也就是将配置类转换为ConfigurationClass阶段
//REGISTER_BEAN:代表配置类注册为bean阶段,也就是将配置类是否需要在将其注册到IOC容器阶段
if (phase == null)
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata))
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata))
for (String conditionClass : conditionClasses)
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions)
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition)
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
//这里进行matches回调,决定是否继续
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata))
return true;
return false;
【应用场景】
一般@Conditional用来进行Bean构造、注入的限制,直接使用@Conditional的情况并不多见,更多的是使用他的派生注解:
@ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnJava等等
这些都是Spring帮我们实现了的一些常见限制条件,例如依赖某些Bean才进行注册,没有某些Bean才进行注册等等
以上是关于Spring@Conditional详解的主要内容,如果未能解决你的问题,请参考以下文章
14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段