Spring的@Conditional詳解
功能介紹
@Conditional
給想要注入Bean增加限制條件,只有滿足限制條件才會被構(gòu)造并注入到Spring的IOC容器中,通常和@Bean注解一起使用。
使用實(shí)例
Bean類,以及注入Bean的類:
@Component
public class TestConfig {
@Bean
// 注入Bean之前增加限制條件:MyCondition,條件滿足才會構(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)的信息、對象
//獲取ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//獲取類加載器
ClassLoader classLoader = context.getClassLoader();
//獲取當(dāng)前環(huán)境信息
Environment environment = context.getEnvironment();
//獲取bean定義的注冊類
BeanDefinitionRegistry registry = context.getRegistry();
//metadata能取到注解的元信息
metadata.getAnnotations().forEach(a -> {
//注解的class
Class<Annotation> type = a.getType();
//注解對應(yīng)的attribute
Object value = a.getValue("value").get();
});
//返回false表示未滿足條件,不進(jìn)行構(gòu)造和注入;返回true表示滿足條件,正常構(gòu)造和注入
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);
}
}輸出結(jié)果:
//如果MyCondition中返回true,則輸出正常:
testBean = TestBean{id=1}
//如果MyCondition中返回false,則輸出null:
testBean = null
源碼分析
從啟動開始,選取和@Conditional有關(guān)的源碼:
第一步,SpringBoot啟動,并初始化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)造及注冊,其中conditionEvaluator.shouldSkip決定了是否執(zhí)行后續(xù)的Bean構(gòu)造及注冊,如圖:

第三步,條件邏輯處理
這里是@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:代表配置類注冊為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();
}
//這里進(jìn)行matches回調(diào),決定是否繼續(xù)
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}應(yīng)用場景
一般@Conditional用來進(jìn)行Bean構(gòu)造、注入的限制,直接使用@Conditional的情況并不多見,更多的是使用他的派生注解: @ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnJava等等
這些都是Spring幫我們實(shí)現(xiàn)了的一些常見限制條件,例如依賴某些Bean才進(jìn)行注冊,沒有某些Bean才進(jìn)行注冊等等
到此這篇關(guān)于Spring的@Conditional詳解的文章就介紹到這了,更多相關(guān)@Conditional注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot+Nginx+MySQL容器化實(shí)戰(zhàn)指南
這篇文章主要介紹了Spring Boot+Nginx+MySQL容器化實(shí)戰(zhàn)指南,本文通過思路代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2026-03-03
Spring Boot/Spring Cloud 應(yīng)用日志書寫詳細(xì)實(shí)例指南
這篇文章主要介紹了Spring Boot/Spring Cloud 應(yīng)用日志書寫詳細(xì)指南,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2026-03-03
Eclipse 開發(fā)java 出現(xiàn)Failed to create the Java Virtual Machine錯誤
這篇文章主要介紹了Eclipse 開發(fā)java 出現(xiàn)Failed to create the Java Virtual Machine錯誤解決辦法的相關(guān)資料,需要的朋友可以參考下2017-04-04
使用Spring實(shí)現(xiàn)@Value注入靜態(tài)字段
這篇文章主要介紹了使用Spring實(shí)現(xiàn)@Value注入靜態(tài)字段方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
Kotlin常用函數(shù)let,with,run,apply用法與區(qū)別案例詳解
這篇文章主要介紹了Kotlin常用函數(shù)let,with,run,apply用法與區(qū)別案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09
Java使用Spire.Doc實(shí)現(xiàn)Word轉(zhuǎn)PDF的完整方案
在OA系統(tǒng)開發(fā)、電子合同生成等場景中,Java開發(fā)者在處理文檔自動化時(shí)最常遇到的痛點(diǎn):生成的Word文檔通過傳統(tǒng)POI轉(zhuǎn)換PDF時(shí)格式丟失,本文介紹的Spire.Doc for Java方案能保持原版格式,實(shí)現(xiàn)Word轉(zhuǎn)PDF,文中通過代碼講解的非常詳細(xì),需要的朋友可以參考下2025-08-08
Mybatis遷移到Mybatis-Plus的實(shí)現(xiàn)方法
這篇文章主要介紹了Mybatis遷移到Mybatis-Plus的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08

