最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot條件注解@Conditional詳細(xì)解析

 更新時(shí)間:2023年11月27日 10:57:38   作者:恒奇恒毅  
這篇文章主要介紹了SpringBoot條件注解@Conditional詳細(xì)解析,@Conditional是Spring4.0提供的一個(gè)用于條件裝配的注解,其定義了一個(gè)Condition的數(shù)組,只有當(dāng)數(shù)組所有的條件都滿足的時(shí)候,組件才會(huì)被導(dǎo)入容器,需要的朋友可以參考下

一、條件注解@Conditional

@Conditional是Spring4.0提供的一個(gè)用于條件裝配的注解,其定義了一個(gè)Condition的數(shù)組,只有當(dāng)數(shù)組所有的條件都滿足的時(shí)候,組件才會(huì)被導(dǎo)入容器。

/**
 * Indicates that a component is only eligible for registration when all
 * {@linkplain #value specified conditions} match.
 *
 * <p>A <em>condition</em> is any state that can be determined programmatically
 * before the bean definition is due to be registered (see {@link Condition} for details).
 *
 * <p>The {@code @Conditional} annotation may be used in any of the following ways:
 * <ul>
 * <li>as a type-level annotation on any class directly or indirectly annotated with
 * {@code @Component}, including {@link Configuration @Configuration} classes</li>
 * <li>as a meta-annotation, for the purpose of composing custom stereotype
 * annotations</li>
 * <li>as a method-level annotation on any {@link Bean @Bean} method</li>
 * </ul>
 *
 * <p>If a {@code @Configuration} class is marked with {@code @Conditional},
 * all of the {@code @Bean} methods, {@link Import @Import} annotations, and
 * {@link ComponentScan @ComponentScan} annotations associated with that
 * class will be subject to the conditions.
 *
 * <p><strong>NOTE</strong>: Inheritance of {@code @Conditional} annotations
 * is not supported; any conditions from superclasses or from overridden
 * methods will not be considered. In order to enforce these semantics,
 * {@code @Conditional} itself is not declared as
 * {@link java.lang.annotation.Inherited @Inherited}; furthermore, any
 * custom <em>composed annotation</em> that is meta-annotated with
 * {@code @Conditional} must not be declared as {@code @Inherited}.
 *
 * @author Phillip Webb
 * @author Sam Brannen
 * @since 4.0
 * @see Condition
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	/**
	 * All {@link Condition}s that must {@linkplain Condition#matches match}
	 * in order for the component to be registered.
	 */
	Class<? extends Condition>[] value();
}

@Conditional注解可以有兩種使用方法:

  • 類型級(jí)別,任意直接或者間接標(biāo)注了@Conponent注解的類或者注解,比如@Configuration或者@Profile
  • 方法級(jí)別,任意標(biāo)注了@Bean注解的方法

如果一個(gè)@Configuration類標(biāo)注了@Conditional,那么這個(gè)類所有的@Bean方法,@ComponentScan和@Import的結(jié)果都受@Conditional注解的條件約束。 特別要注意的是:@Conditional是不支持繼承的,任何父類的條件注解或者方法繼承的條件注解都不會(huì)生效。為了強(qiáng)化這些語義,@Conditional本身并沒有標(biāo)注@Inherited。另外,任何使用了@Conditional注解的組合注解都不能聲明為@Inherited。

二、條件判斷接口Condition

@Conditional注解依賴于Condition接口,該接口提供真正的條件判斷邏輯。

/**
 * A single {@code condition} that must be {@linkplain #matches matched} in order
 * for a component to be registered.
 *
 * <p>Conditions are checked immediately before the bean-definition is due to be
 * registered and are free to veto registration based on any criteria that can
 * be determined at that point.
 *
 * <p>Conditions must follow the same restrictions as {@link BeanFactoryPostProcessor}
 * and take care to never interact with bean instances. For more fine-grained control
 * of conditions that interact with {@code @Configuration} beans consider the
 * {@link ConfigurationCondition} interface.
 *
 * @author Phillip Webb
 * @since 4.0
 * @see ConfigurationCondition
 * @see Conditional
 * @see ConditionContext
 */
public interface Condition {
	/**
	 * Determine if the condition matches.
	 * @param context the condition context
	 * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
	 * or {@link org.springframework.core.type.MethodMetadata method} being checked.
	 * @return {@code true} if the condition matches and the component can be registered
	 * or {@code false} to veto registration.
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

Condition接口傳遞兩個(gè)參數(shù)ConditionContext和AnnotatedTypeMetadata,在Condition實(shí)現(xiàn)類中可以直接使用這兩個(gè)參數(shù),獲取環(huán)境、容器、類等相關(guān)信息。

1. ConditionContext

/**
 * Context information for use by {@link Condition}s.
 *
 * @author Phillip Webb
 * @since 4.0
 */
public interface ConditionContext {
	/**
	 * Return the {@link BeanDefinitionRegistry} that will hold the bean definition
	 * should the condition match or {@code null} if the registry is not available.
	 * @return the registry or {@code null}
	 */
	BeanDefinitionRegistry getRegistry();
	/**
	 * Return the {@link ConfigurableListableBeanFactory} that will hold the bean
	 * definition should the condition match or {@code null} if the bean factory
	 * is not available.
	 * @return the bean factory or {@code null}
	 */
	ConfigurableListableBeanFactory getBeanFactory();
	/**
	 * Return the {@link Environment} for which the current application is running
	 * or {@code null} if no environment is available.
	 * @return the environment or {@code null}
	 */
	Environment getEnvironment();
	/**
	 * Return the {@link ResourceLoader} currently being used or {@code null}
	 * if the resource loader cannot be obtained.
	 * @return a resource loader or {@code null}
	 */
	ResourceLoader getResourceLoader();
	/**
	 * Return the {@link ClassLoader} that should be used to load additional
	 * classes or {@code null} if the default classloader should be used.
	 * @return the class loader or {@code null}
	 */
	ClassLoader getClassLoader();
}

CondtitionContext可以獲取到BeanDefinitionRegistry、ConfigurableListableBeanFactory、Environment、ResourceLoader、ClassLoader這些環(huán)境相關(guān)的信息。

2. AnnotatedTypeMetadata

public interface AnnotatedTypeMetadata {

    // 根據(jù)“全類名”判斷是否被指定 直接注解或元注解 標(biāo)注
    boolean isAnnotated(String annotationName);
    
    // 根據(jù)”全類名“獲取所有注解屬性(包括元注解)
    @Nullable
    Map<String, Object> getAnnotationAttributes(String annotationName);
    
    @Nullable
    // 同上,但是第二個(gè)參數(shù)傳 true 時(shí)會(huì)把屬性中對(duì)應(yīng)值為 Class 的值
    // 轉(zhuǎn)為 字符串,避免需要預(yù)先加載對(duì)應(yīng) Class
    Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);
    
    @Nullable
    // 同上,MultiValueMap 是一個(gè) key 可以對(duì)應(yīng)多個(gè) value 的變種 map
    MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
    @Nullable
    MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);

}

頂層接口,可被注解標(biāo)注類型(類、方法)元數(shù)據(jù)的抽象,提供了兩個(gè)核心方法:

  • 根據(jù) 全類名 判斷是否被指定注解標(biāo)注
  • 根據(jù) 全類名 返回指定注解的屬性集合(包括元注解)

三、@Conditional如何被解析,Condition方法何時(shí)調(diào)用?

@Conditional和Condition的相關(guān)邏輯是在類ConditionEvaluator#中實(shí)現(xiàn)的。

class ConditionEvaluator {
	private final ConditionContextImpl context;
	/**
	 * Create a new {@link ConditionEvaluator} instance.
	 */
	public ConditionEvaluator(BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {
		this.context = new ConditionContextImpl(registry, environment, resourceLoader);
	}
	/**
	 * Determine if an item should be skipped based on {@code @Conditional} annotations.
	 * The {@link ConfigurationPhase} will be deduced from the type of item (i.e. a
	 * {@code @Configuration} class will be {@link ConfigurationPhase#PARSE_CONFIGURATION})
	 * @param metadata the meta data
	 * @return if the item should be skipped
	 */
	public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
		return shouldSkip(metadata, null);
	}
	/**
	 * Determine if an item should be skipped based on {@code @Conditional} annotations.
	 * @param metadata the meta data
	 * @param phase the phase of the call
	 * @return if the item should be skipped
	 */
	public boolean shouldSkip(AnnotatedTypeMetadata metadata, 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<Condition> conditions = new ArrayList<Condition>();
		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) {
				if (!condition.matches(this.context, metadata)) {
					return true;
				}
			}
		}
		return false;
	}
	@SuppressWarnings("unchecked")
	private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
		MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);
		Object values = (attributes != null ? attributes.get("value") : null);
		return (List<String[]>) (values != null ? values : Collections.emptyList());
	}
	private Condition getCondition(String conditionClassName, ClassLoader classloader) {
		Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName, classloader);
		return (Condition) BeanUtils.instantiateClass(conditionClass);
	}
	/**
	 * Implementation of a {@link ConditionContext}.
	 */
	private static class ConditionContextImpl implements ConditionContext {
		private final BeanDefinitionRegistry registry;
		private final ConfigurableListableBeanFactory beanFactory;
		private final Environment environment;
		private final ResourceLoader resourceLoader;
		public ConditionContextImpl(BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {
			this.registry = registry;
			this.beanFactory = deduceBeanFactory(registry);
			this.environment = (environment != null ? environment : deduceEnvironment(registry));
			this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
		}
		private ConfigurableListableBeanFactory deduceBeanFactory(BeanDefinitionRegistry source) {
			if (source instanceof ConfigurableListableBeanFactory) {
				return (ConfigurableListableBeanFactory) source;
			}
			if (source instanceof ConfigurableApplicationContext) {
				return (((ConfigurableApplicationContext) source).getBeanFactory());
			}
			return null;
		}
		private Environment deduceEnvironment(BeanDefinitionRegistry source) {
			if (source instanceof EnvironmentCapable) {
				return ((EnvironmentCapable) source).getEnvironment();
			}
			return null;
		}
		private ResourceLoader deduceResourceLoader(BeanDefinitionRegistry source) {
			if (source instanceof ResourceLoader) {
				return (ResourceLoader) source;
			}
			return null;
		}
		@Override
		public BeanDefinitionRegistry getRegistry() {
			return this.registry;
		}
		@Override
		public ConfigurableListableBeanFactory getBeanFactory() {
			return this.beanFactory;
		}
		@Override
		public Environment getEnvironment() {
			return this.environment;
		}
		@Override
		public ResourceLoader getResourceLoader() {
			return this.resourceLoader;
		}
		@Override
		public ClassLoader getClassLoader() {
			if (this.resourceLoader != null) {
				return this.resourceLoader.getClassLoader();
			}
			if (this.beanFactory != null) {
				return this.beanFactory.getBeanClassLoader();
			}
			return null;
		}
	}
}

而該類根據(jù)構(gòu)造方法的調(diào)用點(diǎn),可知以下幾個(gè)類會(huì)使用到。

在這里插入圖片描述

  • AnnotatedBeanDefinitionReader 注解標(biāo)注時(shí)候
  • ClassPathScanningCandidateComponentProvider注解掃描時(shí)候
  • ConfigurationClassBeanDefinitionReader、ConfigurationClassParser(ConfigurationClassPostProcessor) 解析Configuration注解的過程中

四、典型應(yīng)用 @Profile

@Profile就是典型地基于@Conditional的擴(kuò)展,其條件邏輯封裝在ProfileCondition中

class ProfileCondition implements Condition {
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		if (context.getEnvironment() != null) {
			MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
			if (attrs != null) {
				for (Object value : attrs.get("value")) {
					if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
						return true;
					}
				}
				return false;
			}
		}
		return true;
	}
}

Springboot中的應(yīng)用

在這里插入圖片描述

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

相關(guān)文章

  • Springboot和Jpa實(shí)現(xiàn)學(xué)生CRUD操作代碼實(shí)例

    Springboot和Jpa實(shí)現(xiàn)學(xué)生CRUD操作代碼實(shí)例

    這篇文章主要介紹了Springboot和Jpa實(shí)現(xiàn)學(xué)生CRUD操作代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Spring中Properties的配置方式

    Spring中Properties的配置方式

    這篇文章主要介紹了Spring中Properties的配置方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-02-02
  • 詳解Java異常處理中throw與throws關(guān)鍵字的用法區(qū)別

    詳解Java異常處理中throw與throws關(guān)鍵字的用法區(qū)別

    這篇文章主要介紹了詳解Java異常處理中throw與throws關(guān)鍵字的用法區(qū)別,這也是Java面試題目中的常客,需要的朋友可以參考下
    2015-11-11
  • Java之NIO基本簡介

    Java之NIO基本簡介

    這篇文章主要介紹了Java之NIO基本簡介,文中給大家講到了NIO?與?BIO的比較結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • Java中生產(chǎn)者消費(fèi)者問題總結(jié)

    Java中生產(chǎn)者消費(fèi)者問題總結(jié)

    這篇文章主要介紹了Java中生產(chǎn)者消費(fèi)者問題總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Spring?Boot?基于?SAML?實(shí)現(xiàn)單點(diǎn)登錄原理解析

    Spring?Boot?基于?SAML?實(shí)現(xiàn)單點(diǎn)登錄原理解析

    基于SAML在 Spring Boot 中實(shí)現(xiàn)單點(diǎn)登錄雖然有一定的復(fù)雜度,但能為企業(yè)級(jí)應(yīng)用帶來強(qiáng)大的身份驗(yàn)證和授權(quán)功能,本文將詳細(xì)介紹在 Spring Boot中基于SAML實(shí)現(xiàn)單點(diǎn)登錄的原理、方式、優(yōu)缺點(diǎn)及注意事項(xiàng),并給出具體代碼示例,感興趣的朋友一起看看吧
    2025-06-06
  • Java設(shè)計(jì)模式之解釋器模式

    Java設(shè)計(jì)模式之解釋器模式

    這篇文章介紹了Java設(shè)計(jì)模式之解釋器模式,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-10-10
  • 將Maven鏡像源更改為阿里鏡像的操作步驟

    將Maven鏡像源更改為阿里鏡像的操作步驟

    在軟件開發(fā)中,Maven是一個(gè)流行的項(xiàng)目管理工具,它允許你從Maven中央倉庫下載所需的依賴包,然而,由于地理位置或網(wǎng)絡(luò)狀況的差異,從默認(rèn)的Maven中央倉庫下載依賴包的速度可能會(huì)較慢,所
    2025-01-01
  • java數(shù)據(jù)結(jié)構(gòu)與算法之快速排序詳解

    java數(shù)據(jù)結(jié)構(gòu)與算法之快速排序詳解

    這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之快速排序,結(jié)合實(shí)例形式詳細(xì)分析了快速排序的原理、實(shí)現(xiàn)步驟、相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2017-05-05
  • Sequelize 常用操作詳解及實(shí)例代碼

    Sequelize 常用操作詳解及實(shí)例代碼

    這篇文章主要介紹了Sequelize 常用操作詳解及實(shí)例代碼的相關(guān)資料,希望能幫助到大家,需要的朋友可以參考下
    2016-11-11

最新評(píng)論

漳州市| 绥德县| 缙云县| 抚顺市| 茶陵县| 肃南| 府谷县| 宁陵县| 田阳县| 镇安县| 包头市| 蒙城县| 沽源县| 敖汉旗| 神木县| 巨野县| 抚顺县| 石嘴山市| 凤冈县| 句容市| 宜兰市| 阿勒泰市| 永城市| 东丽区| 平罗县| 文昌市| 娄底市| 南开区| 津市市| 霍邱县| 郸城县| 玛沁县| 新野县| 毕节市| 河北区| 宿松县| 凤凰县| 长顺县| 南安市| 巫溪县| 浦北县|