亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring的@Conditional詳解

 更新時(shí)間:2024年01月03日 10:27:23   作者:猿人林克  
這篇文章主要介紹了Spring的@Conditional詳解,給想要注入Bean增加限制條件,只有滿足限制條件才會(huì)被構(gòu)造并注入到Spring的IOC容器中,通常和@Bean注解一起使用,需要的朋友可以參考下

功能介紹

@Conditional

給想要注入Bean增加限制條件,只有滿足限制條件才會(huì)被構(gòu)造并注入到Spring的IOC容器中,通常和@Bean注解一起使用。

使用實(shí)例

Bean類,以及注入Bean的類:

@Component
public class TestConfig {
    @Bean
    // 注入Bean之前增加限制條件:MyCondition,條件滿足才會(huì)構(gòu)造TestBean同時(shí)注入
    @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相關(guān)的信息、對(duì)象
        //獲取ioc使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //獲取類加載器
        ClassLoader classLoader = context.getClassLoader();
        //獲取當(dāng)前環(huán)境信息
        Environment environment = context.getEnvironment();
        //獲取bean定義的注冊(cè)類
        BeanDefinitionRegistry registry = context.getRegistry();
        //metadata能取到注解的元信息
        metadata.getAnnotations().forEach(a -> {
            //注解的class
            Class<Annotation> type = a.getType();
            //注解對(duì)應(yīng)的attribute
            Object value = a.getValue("value").get();
        });
        //返回false表示未滿足條件,不進(jìn)行構(gòu)造和注入;返回true表示滿足條件,正常構(gòu)造和注入
        return false;
    }
}

測(cè)試類:

@SpringBootTest
class MyConsul1ApplicationTests {
	//required=false:表示如果testBean在容器中不存在,也不會(huì)異常中斷,而是單純的testBean=null而已
	@Autowired(required=false)
	private TestBean testBean;
	@Test
	public void test() {
		System.out.println("testBean = " + testBean);
	}
}

輸出結(jié)果:

//如果MyCondition中返回true,則輸出正常:
testBean = TestBean{id=1}
//如果MyCondition中返回false,則輸出null:
testBean = null

源碼分析

從啟動(dòng)開始,選取和@Conditional有關(guān)的源碼:

第一步,SpringBoot啟動(dòng),并初始化applicationContext

SpringApplication.run
->
SpringApplication.createApplicationContext
->
applicationContext = new AnnotationConfigServletWebServerApplicationContext
->
applicationContext.reader = new AnnotatedBeanDefinitionReader
->
applicationContext.reader. conditionEvaluator = new ConditionEvaluator

這一步,主要是初始化applicationContext,其中包括: 用來進(jìn)行注解Bean解析的reader處理器(AnnotatedBeanDefinitionReader),以及reader中的條件處理器(conditionEvaluator),如圖:

在這里插入圖片描述

第二步,applicationContext預(yù)處理

SpringApplication.prepareContext
->
SpringApplication.load
->
SpringApplication.createBeanDefinitionLoader
->
BeanDefinitionLoader.load
->
AnnotatedBeanDefinitionReader.register -> registerBean -> doRegisterBean
->
conditionEvaluator.shouldSkip
->
BeanDefinitionReaderUtils.registerBeanDefinition
->
registry.registerBeanDefinition

這一步,主要是要進(jìn)行Bean的構(gòu)造及注冊(cè),其中conditionEvaluator.shouldSkip決定了是否執(zhí)行后續(xù)的Bean構(gòu)造及注冊(cè),如圖:

在這里插入圖片描述

第三步,條件邏輯處理

這里是@Conditional注解的核心處理過程,主要就是通過回調(diào)我們自定義的Condition.matches方法來實(shí)現(xiàn):

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:代表解析配置類階段,也就是將配置類轉(zhuǎn)換為ConfigurationClass階段
//REGISTER_BEAN:代表配置類注冊(cè)為bean階段,也就是將配置類是否需要在將其注冊(cè)到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();
			}
			//這里進(jìn)行matches回調(diào),決定是否繼續(xù)
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}
		return false;
	}

應(yīng)用場(chǎng)景

一般@Conditional用來進(jìn)行Bean構(gòu)造、注入的限制,直接使用@Conditional的情況并不多見,更多的是使用他的派生注解: @ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnJava等等

這些都是Spring幫我們實(shí)現(xiàn)了的一些常見限制條件,例如依賴某些Bean才進(jìn)行注冊(cè),沒有某些Bean才進(jìn)行注冊(cè)等等

到此這篇關(guān)于Spring的@Conditional詳解的文章就介紹到這了,更多相關(guān)@Conditional注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論