Spring的@Conditional详解

 更新时间:2024年01月03日 10:27:23   作者:猿人林克  
这篇文章主要介绍了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注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java在OJ时运行超时的问题解决方案

    Java在OJ时运行超时的问题解决方案

    Java语言什么都好,就是在OJ的时候真的是太慢了,今天来讲解一种让Java运行速度快速提高的方法,感兴趣的朋友一起看看吧
    2023-11-11
  • 浅谈java对象之间相互转化的多种方式

    浅谈java对象之间相互转化的多种方式

    这篇文章主要介绍了浅谈java对象之间相互转化的多种方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Spring Boot详细打印启动时异常堆栈信息详析

    Spring Boot详细打印启动时异常堆栈信息详析

    这篇文章主要给大家介绍了关于Spring Boot详细打印启动时异常堆栈信息的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-10-10
  • Netty分布式pipeline传播inbound事件源码分析

    Netty分布式pipeline传播inbound事件源码分析

    这篇文章主要为大家介绍了Netty分布式pipeline传播inbound事件的源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • SpringBoot使用WebJars统一管理静态资源的方法

    SpringBoot使用WebJars统一管理静态资源的方法

    这篇文章主要介绍了SpringBoot使用WebJars统一管理静态资源的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • Java restTemplate发送get请求query参数传递问题解决

    Java restTemplate发送get请求query参数传递问题解决

    这篇文章主要为大家介绍了Java restTemplate发送get请求query参数传递问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • maven中pom.xml详细介绍

    maven中pom.xml详细介绍

    最近在学习maven,这篇文章主要介绍了maven中pom.xml详细介绍,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • JAVA利用接口实现多继承问题的代码实操演示

    JAVA利用接口实现多继承问题的代码实操演示

    Java语言并不支持多继承,这是由于多继承会带来许多复杂的问题,例如"菱形问题"等,下面这篇文章主要给大家介绍了关于JAVA利用接口实现多继承问题的相关资料,需要的朋友可以参考下
    2024-03-03
  • 聊一聊new对象与Spring对bean的初始化的差别

    聊一聊new对象与Spring对bean的初始化的差别

    这篇文章主要介绍了聊一聊new对象与Spring对bean的初始化的差别,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • Java实现在线聊天室(层层递进)

    Java实现在线聊天室(层层递进)

    这篇文章主要为大家详细介绍了Java实现在线聊天室,层层递进,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-09-09

最新评论