java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > @Conditional注解

Spring的@Conditional详解

作者:猿人林克

这篇文章主要介绍了Spring的@Conditional详解,给想要注入Bean增加限制条件,只有满足限制条件才会被构造并注入到Spring的IOC容器中,通常和@Bean注解一起使用,需要的朋友可以参考下

功能介绍

@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 = TestBean{id=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详解的文章就介绍到这了,更多相关@Conditional注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文