日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
深度解析@Conditional注解

一、學(xué)習(xí)指引

Spring是如何根據(jù)條件創(chuàng)建Bean的?

創(chuàng)新互聯(lián)專(zhuān)注為客戶(hù)提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都網(wǎng)站制作、成都網(wǎng)站設(shè)計(jì)、外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè)、巴宜網(wǎng)絡(luò)推廣、小程序開(kāi)發(fā)、巴宜網(wǎng)絡(luò)營(yíng)銷(xiāo)、巴宜企業(yè)策劃、巴宜品牌公關(guān)、搜索引擎seo、人物專(zhuān)訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供巴宜建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com

日常工作過(guò)程中,相信這種情況是最常見(jiàn)的:根據(jù)某個(gè)或某些條件來(lái)執(zhí)行相應(yīng)的邏輯。換句話說(shuō),會(huì)通過(guò)if-else語(yǔ)句來(lái)執(zhí)行一定的業(yè)務(wù)邏輯功能。

在Spring中,就有這樣一個(gè)注解,它支持根據(jù)一定的條件來(lái)創(chuàng)建對(duì)應(yīng)的Bean對(duì)象,并將Bean對(duì)象注冊(cè)到IOC容器中。滿(mǎn)足條件的Bean就會(huì)被注冊(cè)到IOC容器中,不滿(mǎn)足條件的Bean就不會(huì)被注冊(cè)到IOC容器中。這個(gè)注解就是@Conditional注解,本章,就對(duì)@Conditional注解進(jìn)行簡(jiǎn)單的介紹。

二、注解說(shuō)明

關(guān)于@Conditional注解的一點(diǎn)點(diǎn)說(shuō)明~~

Spring提供的@Conditional注解支持按照條件向IOC容器中注冊(cè)Bean,滿(mǎn)足條件的Bean就會(huì)被注冊(cè)到IOC容器中,不滿(mǎn)足條件的Bean就不會(huì)被注冊(cè)到IOC容器中。

2.1 注解源碼

@Conditional注解可以標(biāo)注到類(lèi)或方法上,能夠?qū)崿F(xiàn)按照條件向IOC容器中注冊(cè)Bean。源碼詳見(jiàn):org.springframework.context.annotation.Conditional。

/**
* @author Phillip Webb
* @author Sam Brannen
* @since 4.0
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class[] value();
}

從@Conditional注解的源碼可以看出,@Conditional注解是從Spring 4.0版本開(kāi)始提供的注解。在@Conditional注解注解中只提供了一個(gè)Class數(shù)組類(lèi)型的value屬性,具體含義如下所示。

  • value:指定Condition接口的實(shí)現(xiàn)類(lèi),Condition接口的實(shí)現(xiàn)類(lèi)中需要編寫(xiě)具體代碼實(shí)現(xiàn)向Spring中注入Bean的條件。

2.2 使用場(chǎng)景

如果使用Spring開(kāi)發(fā)的應(yīng)用程序需要根據(jù)不同的運(yùn)行環(huán)境來(lái)讀取不同的配置信息,例如在Windows操作系統(tǒng)上需要讀取Windows操作系統(tǒng)的環(huán)境信息,在MacOS操作系統(tǒng)上需要讀取MacOS操作系統(tǒng)的環(huán)境信息。此時(shí),就可以使用@Conditional注解實(shí)現(xiàn)。

另外,@Conditional注解還有如下一些使用場(chǎng)景:

  • 可以作為類(lèi)級(jí)別的注解直接或者間接的與@Component相關(guān)聯(lián),包括@Configuration類(lèi)。
  • 可以作為元注解,用于自動(dòng)編寫(xiě)構(gòu)造性注解。
  • 作為方法級(jí)別的注解,作用在任何@Bean的方法上。

三、使用案例

@Conditional注解案例實(shí)戰(zhàn)~~

Spring的@Conditional注解可以標(biāo)注到類(lèi)或方法上,并且會(huì)實(shí)現(xiàn)按照一定的條件將對(duì)應(yīng)的Bean注入到IOC容器中。所以,本節(jié),會(huì)列舉無(wú)條件(不加@Conditional注解)、@Conditional注解標(biāo)注到方法上和@Conditional注解標(biāo)注到類(lèi)上以及將@Conditional注解同時(shí)標(biāo)注到類(lèi)上和方法上等四個(gè)主要案例。

3.1 無(wú)條件案例

本節(jié),主要實(shí)現(xiàn)不使用@Conditional注解時(shí),向IOC容器中注入Bean的案例,具體實(shí)現(xiàn)步驟如下所示。

(1)新增Founder類(lèi)

Founder類(lèi)的源碼詳見(jiàn):spring-annotation-chapter-08工程下的io.binghe.spring.annotation.chapter08.bean.Founder。

public class Founder {
private String name;
public Founder(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + '}';
}
}

可以看到,F(xiàn)ounder類(lèi)就是Java中的一個(gè)普通實(shí)體類(lèi)。

(2)新增ConditionalConfig類(lèi)

ConditionalConfig類(lèi)的源碼詳見(jiàn):spring-annotation-chapter-08工程下的io.binghe.spring.annotation.chapter08.config.ConditionalConfig。

@Configuration
public class ConditionalConfig {
@Bean(name = "bill")
public Founder windowsFounder(){
return new Founder("Bill Gates");
}
@Bean(name = "jobs")
public Founder macosFounder(){
return new Founder("Steve Jobs");
}
}

可以看到,ConditionalConfig類(lèi)是一個(gè)Spring的配置類(lèi),并且在ConditionalConfig類(lèi)中使用@Bean注解創(chuàng)建了兩個(gè)Bean對(duì)象,并注冊(cè)到IOC容器中,一個(gè)Bean的名稱(chēng)為bill,另一個(gè)Bean的名稱(chēng)為jobs。

(3)新增ConditionalTest類(lèi)

ConditionalTest類(lèi)的源碼詳見(jiàn):spring-annotation-chapter-08工程下的io.binghe.spring.annotation.chapter08.ConditionalTest。

public class ConditionalTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionalConfig.class);
String[] definitionNames = context.getBeanDefinitionNames();
Arrays.stream(definitionNames).forEach((definitionName) -> System.out.println(definitionName));
}
}

可以看到,在ConditionalTest類(lèi)的main()方法中,會(huì)打印注入到IOC容器中的Bean名稱(chēng)。

(4)運(yùn)行ConditionalTest類(lèi)

運(yùn)行ConditionalTest類(lèi)的main()方法,輸出的結(jié)果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
conditionalConfig
bill
jobs

從輸出的結(jié)果信息可以看出,向IOC容器中注入了名稱(chēng)為conditionalConfig、bill和jobs的Bean。

說(shuō)明:沒(méi)設(shè)置@Conditional注解時(shí),會(huì)向Spring容器中注入所有使用@Bean注解創(chuàng)建的Bean。

3.2 標(biāo)注到方法上的案例

本節(jié),主要實(shí)現(xiàn)將@Conditional注解標(biāo)注到方法上,向IOC容器中注入Bean的案例,具體實(shí)現(xiàn)步驟如下所示。

注意:本節(jié)的案例是在3.1節(jié)的基礎(chǔ)上進(jìn)行完善,在對(duì)應(yīng)的方法上添加@Conditional注解。

(1)新增WindowsCondition類(lèi)

WindowsCondition類(lèi)的源碼詳見(jiàn):spring-annotation-chapter-08工程下的io.binghe.spring.annotation.chapter08.condition.WindowsCondition。

public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String osName = context.getEnvironment().getProperty("os.name");
return osName.toLowerCase().contains("windows");
}
}

可以看到,WindowsCondition類(lèi)實(shí)現(xiàn)了Condition接口,并實(shí)現(xiàn)了matches()方法。在matches()方法中,通過(guò)Spring的環(huán)境變量讀取操作系統(tǒng)名稱(chēng),如果操作系統(tǒng)名稱(chēng)中包含windows就返回true,否則返回false。當(dāng)返回true時(shí),使用@Conditional注解指定的條件為WindowsCondition類(lèi)的Class對(duì)象的Bean會(huì)被創(chuàng)建并注入到IOC容器中。

(2)新增MacosCondition類(lèi)

MacosCondition類(lèi)的源碼詳見(jiàn):spring-annotation-chapter-08工程下的io.binghe.spring.annotation.chapter08.condition.MacosCondition。

public class MacosCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String osName = context.getEnvironment().getProperty("os.name");
return osName.toLowerCase().contains("mac");
}
}

可以看到,MacosCondition類(lèi)實(shí)現(xiàn)了Condition接口,并實(shí)現(xiàn)了matches()方法。在matches()方法中,通過(guò)Spring的環(huán)境變量讀取操作系統(tǒng)名稱(chēng),如果操作系統(tǒng)名稱(chēng)中包含mac就返回true,否則返回false。當(dāng)返回true時(shí),使用@Conditional注解指定的條件為MacosCondition類(lèi)的Class對(duì)象的Bean會(huì)被創(chuàng)建并注入到IOC容器中。

(3)修改ConditionalConfig類(lèi)

在ConditionalConfig類(lèi)的方法上標(biāo)注@Conditional注解,修改后的源碼如下所示。

@Bean(name = "bill")
@Conditional(value = {WindowsCondition.class})
public Founder windowsFounder(){
System.out.println("創(chuàng)建名稱(chēng)為bill的Bean對(duì)象");
return new Founder("Bill Gates");
}

@Bean(name = "jobs")
@Conditional(value = {MacosCondition.class})
public Founder macosFounder(){
System.out.println("創(chuàng)建名稱(chēng)為jobs的Bean對(duì)象");
return new Founder("Steve Jobs");
}

可以看到,在創(chuàng)建名稱(chēng)為bill的Bean的方法上標(biāo)注了@Conditional注解,并指定了value的屬性為WindowsCondition類(lèi)的class對(duì)象。在創(chuàng)建名稱(chēng)為jobs的Bean的方法上標(biāo)注了@Conditional注解,并指定了value的屬性為MacosCondition類(lèi)的class對(duì)象。

(4)運(yùn)行ConditionalTest類(lèi)

運(yùn)行ConditionalTest類(lèi)的main()方法,輸出的結(jié)果信息如下所示。

創(chuàng)建名稱(chēng)為bill的Bean對(duì)象
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
conditionalConfig
bill

可以看到,由于我的電腦是Windows操作系統(tǒng),所以,打印出的Bean名稱(chēng)包含conditionalConfig和bill,不包含jobs。

說(shuō)明:@Conditional注解標(biāo)注到使用@Bean創(chuàng)建Bean的方法上時(shí),只有滿(mǎn)足@Conditional注解的條件時(shí),才會(huì)執(zhí)行方法體創(chuàng)建Bean對(duì)象并注入到IOC容器中。

3.3 標(biāo)注到類(lèi)上的案例

本節(jié),主要實(shí)現(xiàn)將@Conditional注解標(biāo)注到類(lèi)上,向IOC容器中注入Bean的案例,具體實(shí)現(xiàn)步驟如下所示。

注意:本節(jié)的案例是在3.1節(jié)的基礎(chǔ)上進(jìn)行完善,在對(duì)應(yīng)的類(lèi)上添加@Conditional注解。

(1)修改ConditionalConfig類(lèi)

刪除ConditionalConfig類(lèi)中的方法上的@Conditional注解,并在ConditionalConfig類(lèi)上標(biāo)注@Conditional注解。

@Configuration
@Conditional(value = {MacosCondition.class})
public class ConditionalConfig {
@Bean(name = "bill")
public Founder windowsFounder(){
System.out.println("創(chuàng)建名稱(chēng)為bill的Bean對(duì)象");
return new Founder("Bill Gates");
}
@Bean(name = "jobs")
public Founder macosFounder(){
System.out.println("創(chuàng)建名稱(chēng)為jobs的Bean對(duì)象");
return new Founder("Steve Jobs");
}
}

可以看到,在ConditionalConfig類(lèi)上標(biāo)注了@Conditional注解,并且將value屬性設(shè)置為MacosCondition。也就是說(shuō),當(dāng)前操作系統(tǒng)為MacOS操作系統(tǒng)時(shí),才會(huì)創(chuàng)建名稱(chēng)為bill和jobs的Bean,并將其注入到IOC容器中。

(2)運(yùn)行ConditionalTest類(lèi)

運(yùn)行ConditionalTest類(lèi)的main()方法,輸出的結(jié)果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory

從輸出的結(jié)果信息可以看出,由于我的電腦是Windows操作系統(tǒng),所以,在輸出的Bean名稱(chēng)中,并不包含conditionalConfig、bill和jobs。

說(shuō)明:當(dāng)@Conditional注解標(biāo)注到類(lèi)上時(shí),如果運(yùn)行程序時(shí),不滿(mǎn)足@Conditional注解中指定的條件,則當(dāng)前類(lèi)的所有Bean都不會(huì)被創(chuàng)建,也不會(huì)注入到IOC容器中。

3.4 同時(shí)標(biāo)注到類(lèi)和方法上

本節(jié),主要實(shí)現(xiàn)將@Conditional注解同時(shí)標(biāo)注到類(lèi)和方法上,向IOC容器中注入Bean的案例,具體實(shí)現(xiàn)步驟如下所示。

注意:本節(jié)的案例是在3.1節(jié)的基礎(chǔ)上進(jìn)行完善,在對(duì)應(yīng)的類(lèi)上添加@Conditional注解。

(1)修改ConditionalConfig類(lèi)

在ConditionalConfig類(lèi)的類(lèi)上和方法上同時(shí)標(biāo)注@Conditional注解。如下所示。

@Configuration
@Conditional(value = {MacosCondition.class})
public class ConditionalConfig {
@Bean(name = "bill")
@Conditional(value = {WindowsCondition.class})
public Founder windowsFounder(){
System.out.println("創(chuàng)建名稱(chēng)為bill的Bean對(duì)象");
return new Founder("Bill Gates");
}
@Bean(name = "jobs")
@Conditional(value = {MacosCondition.class})
public Founder macosFounder(){
System.out.println("創(chuàng)建名稱(chēng)為jobs的Bean對(duì)象");
return new Founder("Steve Jobs");
}
}

可以看到,在ConditionalConfig類(lèi)的類(lèi)上和方法上都標(biāo)注了@Conditional注解。其中,在類(lèi)上標(biāo)注的@Conditional注解的條件是當(dāng)前操作系統(tǒng)為MacOS系統(tǒng)。

(2)運(yùn)行ConditionalTest類(lèi)

運(yùn)行ConditionalTest類(lèi)的main()方法,輸出的結(jié)果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory

從輸出的結(jié)果信息可以看出,由于我的電腦是Windows操作系統(tǒng),所以,在輸出的Bean名稱(chēng)中,并不包含conditionalConfig、bill和jobs。

說(shuō)明:當(dāng)@Conditional注解同時(shí)標(biāo)注到類(lèi)和方法上時(shí),如果標(biāo)注到類(lèi)上的@Conditional注解不滿(mǎn)足條件,即使類(lèi)中的方法上標(biāo)注的@Conditional注解滿(mǎn)足條件,也不會(huì)創(chuàng)建Bean,并且也不會(huì)將Bean注入到IOC容器中。

四、源碼時(shí)序圖

結(jié)合時(shí)序圖理解源碼會(huì)事半功倍,你覺(jué)得呢?

本節(jié),就以源碼時(shí)序圖的方式,直觀的感受下@Conditional注解在Spring源碼層面的執(zhí)行流程。@Conditional注解的源碼時(shí)序圖如圖8-1和8-2所示。

五、源碼解析

源碼時(shí)序圖整清楚了,那就整源碼解析唄!

@Conditional注解在Spring源碼層面的執(zhí)行流程,結(jié)合源碼執(zhí)行的時(shí)序圖,會(huì)理解的更加深刻。本節(jié),就簡(jiǎn)單結(jié)合源碼時(shí)序圖簡(jiǎn)單分析下@Conditional注解在Spring源碼層面的執(zhí)行流程。

注意:@Conditional注解在Spring源碼層面的執(zhí)行流程與第7章的5.1節(jié)@DependsOn注解在Spring源碼層面注冊(cè)Bean的執(zhí)行流程大體類(lèi)似,只是在執(zhí)行AnnotatedBeanDefinitionReader類(lèi)的doRegisterBean()方法的邏輯時(shí),略有差異。

(1)解析AnnotatedBeanDefinitionReader類(lèi)的doRegisterBean(ClassbeanClass, String name, Class[] qualifiers, Suppliersupplier, BeanDefinitionCustomizer[] customizers)方法

源碼詳見(jiàn):org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean(ClassbeanClass, String name, Class[] qualifiers, Suppliersupplier, BeanDefinitionCustomizer[] customizers)。

private  void doRegisterBean(Class beanClass, @Nullable String name, @Nullable Class[] qualifiers, @Nullable Supplier supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

可以看到,在AnnotatedBeanDefinitionReader類(lèi)的doRegisterBean()方法中,調(diào)用了conditionEvaluator對(duì)象的shouldSkip()方法判斷是否要忽略當(dāng)前Bean的注冊(cè)。

(2)解析ConditionEvaluator類(lèi)的shouldSkip(AnnotatedTypeMetadata metadata)方法

源碼詳見(jiàn):org.springframework.context.annotation.ConditionEvaluator#shouldSkip(AnnotatedTypeMetadata metadata)

public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null);
}

可以看到,在ConditionEvaluator類(lèi)的shouldSkip()方法中,直接調(diào)用了另一個(gè)重載的shouldSkip()方法。

(3)解析ConditionEvaluator類(lèi)的shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase)方法

源碼詳見(jiàn):org.springframework.context.annotation.ConditionEvaluator#shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase)。

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}

if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}

List 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();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}

return false;
}

可以看到,在shouldSkip()方法中,首先會(huì)判斷類(lèi)或方法上是否標(biāo)注了@Conditional注解,如果沒(méi)有標(biāo)注@Conditional注解,則直接返回false,此時(shí)對(duì)應(yīng)的Bean會(huì)被創(chuàng)建并注入到IOC容器中。

否則,會(huì)解析@Conditional注解中的value屬性設(shè)置的Class對(duì)象,將Class對(duì)象的全類(lèi)名解析到conditionClasses數(shù)組中,遍歷conditionClasses數(shù)組中的每個(gè)元素生成Condition對(duì)象,將Condition對(duì)象存入conditions集合中。后續(xù)會(huì)遍歷conditions集合中的每個(gè)Condition對(duì)象,調(diào)用matches()方法,此處的邏輯與matches()方法的返回值正好相反。

  • matches()方法返回false,則此處返回true,表示對(duì)應(yīng)的Bean不會(huì)被創(chuàng)建,也不會(huì)注入到IOC容器中。
  • matches()方法返回true,則此處返回false,表示對(duì)應(yīng)的Bean會(huì)被創(chuàng)建并且會(huì)注入到IOC容器中。

接下來(lái),就會(huì)回到AnnotatedBeanDefinitionReader類(lèi)的doRegisterBean()方法繼續(xù)執(zhí)行后續(xù)流程,后續(xù)流程與第7章的5.1節(jié)@DependsOn注解在Spring源碼層面注冊(cè)Bean的執(zhí)行流程一致,這里不再贅述。

至此,@Conditional注解在Spring源碼層面的執(zhí)行流程分析完畢。

六、擴(kuò)展注解

@Conditional的擴(kuò)展注解如下所示:

@ConditionalOnBean:僅僅在當(dāng)前上下文中存在某個(gè)對(duì)象時(shí),才會(huì)實(shí)例化一個(gè)Bean。@ConditionalOnClass:某個(gè)class位于類(lèi)路徑上,才會(huì)實(shí)例化一個(gè)Bean。@ConditionalOnExpression:當(dāng)表達(dá)式為true的時(shí)候,才會(huì)實(shí)例化一個(gè)Bean。@ConditionalOnMissingBean:僅僅在當(dāng)前上下文中不存在某個(gè)對(duì)象時(shí),才會(huì)實(shí)例化一個(gè)Bean。@ConditionalOnMissingClass:某個(gè)class類(lèi)路徑上不存在的時(shí)候,才會(huì)實(shí)例化一個(gè)Bean。@ConditionalOnNotWebApplication:不是web應(yīng)用,才會(huì)實(shí)例化一個(gè)Bean。@ConditionalOnBean:當(dāng)容器中有指定Bean的條件下進(jìn)行實(shí)例化。@ConditionalOnMissingBean:當(dāng)容器里沒(méi)有指定Bean的條件下進(jìn)行實(shí)例化。@ConditionalOnClass:當(dāng)classpath類(lèi)路徑下有指定類(lèi)的條件下進(jìn)行實(shí)例化。@ConditionalOnMissingClass:當(dāng)類(lèi)路徑下沒(méi)有指定類(lèi)的條件下進(jìn)行實(shí)例化。@ConditionalOnWebApplication:當(dāng)項(xiàng)目是一個(gè)Web項(xiàng)目時(shí)進(jìn)行實(shí)例化。@ConditionalOnNotWebApplication:當(dāng)項(xiàng)目不是一個(gè)Web項(xiàng)目時(shí)進(jìn)行實(shí)例化。@ConditionalOnProperty:當(dāng)指定的屬性有指定的值時(shí)進(jìn)行實(shí)例化。@ConditionalOnExpression:基于SpEL表達(dá)式的條件判斷。@ConditionalOnJava:當(dāng)JVM版本為指定的版本范圍時(shí)觸發(fā)實(shí)例化。@ConditionalOnResource:當(dāng)類(lèi)路徑下有指定的資源時(shí)觸發(fā)實(shí)例化。@ConditionalOnJndi:在JNDI存在的條件下觸發(fā)實(shí)例化。@ConditionalOnSingleCandidate:當(dāng)指定的Bean在容器中只有一個(gè),或者有多個(gè)但是指定了首選的Bean時(shí)觸發(fā)實(shí)例化。

七、總結(jié)

@Conditional注解介紹完了,我們一起總結(jié)下吧!

本章,首先介紹了@Conditional注解的源碼和使用場(chǎng)景。隨后,列舉了四個(gè)關(guān)于@Conditional注解的案例,分別是:無(wú)條件案例、標(biāo)注到方法上的案例、標(biāo)注到類(lèi)上的案例和同時(shí)標(biāo)注到類(lèi)和方法上的案例。接下來(lái),介紹了@Conditional注解執(zhí)行的源碼時(shí)序圖和源碼流程。

八、思考

既然學(xué)完了,就開(kāi)始思考幾個(gè)問(wèn)題吧?

關(guān)于@Conditional注解,通常會(huì)有如下幾個(gè)經(jīng)典面試題:

  • @Conditional注解的作用是什么?
  • @Conditional注解有哪些使用場(chǎng)景?
  • @Conditional注解與@Profile注解有什么區(qū)別?
  • @Conditional注解在Spring內(nèi)層的執(zhí)行流程?
  • 你在平時(shí)工作中,會(huì)在哪些場(chǎng)景下使用@Conditional注解?
  • 你從@Conditional注解的設(shè)計(jì)中得到了哪些啟發(fā)?

新聞標(biāo)題:深度解析@Conditional注解
URL標(biāo)題:http://m.5511xx.com/article/cccoojj.html