spring @Conditional的使用与扩展源码分析

 更新时间:2022年03月25日 11:08:30   作者:morris131  
这篇文章主要介绍了spring @Conditional的使用与扩展,这里需要注意如果Condition返回的是false,那么spirng就不会对方法或类进行解析,具体源码分析跟随小编一起看看吧

@Conditional的使用

@Conditional可以根据条件来判断是否注入某些Bean。

package com.morris.spring.config;

import com.morris.spring.condition.LinuxCondition;
import com.morris.spring.condition.WindowsCondition;
import com.morris.spring.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConditionalConfig {
	// 如果是windows系统就注入bill
	@Conditional(WindowsCondition.class)
	@Bean(name = "user")
	public User bill() {
		return new User("bill", 22);
	}
	// 如果是linux系统就注入linus
	@Conditional(LinuxCondition.class)
	public User linus() {
		return new User("linus", 20);
}

WindowsCondition和LinuxCondition都需要实现Condition接口。

WindowsCondition

package com.morris.spring.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
    /**
     * 根据条件判断是否注入对应的Bean
     * @param conditionContext 应用上下文
     * @param annotatedTypeMetadata 加了@Conditional注解的方法的元数据信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String osName = conditionContext.getEnvironment().getProperty("os.name");
        if(osName.contains("Windows")) {
            return true;
        }
        return false;
    }
}

LinuxCondition

package com.morris.spring.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String osName = conditionContext.getEnvironment().getProperty("os.name");
        if(osName.contains("linux")) {
            return true;
        }
        return false;
    }
}

如果要测试LinuxCondition并不需要再linux系统下运行,只需要的启动时设置环境参数:-Dos.name=linux

Conditional的扩展

ConditionalOnBean

ConditionalOnBeanc.java

package com.morris.spring.condition;

import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
	Class<?>[] value() default {};
}

OnBeanCondition.java

package com.morris.spring.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class OnBeanCondition implements Condition {
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnBean.class.getName());
		Class<?>[] clazz = (Class<?>[]) annotationAttributes.get("value");
		for (Class<?> aClass : clazz) {
			Map<String, ?> beans = context.getBeanFactory().getBeansOfType(aClass);
			if(beans.isEmpty()) {
				return false;
			}
		}
		return true;
	}
}

ConditionalOnProperty

ConditionalOnProperty.java

package com.morris.spring.condition;

import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
	String[] value() default {};
}

OnPropertyCondition.java

package com.morris.spring.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class OnPropertyCondition implements Condition {
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnProperty.class.getName());
		String[] propertyArray = (String[]) annotationAttributes.get("value");
		for (String property : propertyArray) {
			if(!context.getEnvironment().containsProperty(property)) {
				return false;
			}
		}
		return true;
	}
}

源码分析

如果Condition返回的是false,那么spirng就不会对方法或类进行解析。

org.springframework.context.annotation.ConditionEvaluator#shouldSkip

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
	// 判断类或方法上面是否有@Conditional注解
	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<>();
	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();
		// 调用condition.matches方法
		if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
			return true;
	return false;
}

到此这篇关于spring @Conditional的使用与扩展的文章就介绍到这了,更多相关spring @Conditional使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot实现异步消息处理的代码示例

    SpringBoot实现异步消息处理的代码示例

    在现代应用程序中,异步消息处理是一项至关重要的任务。它可以提高应用程序的性能、可伸缩性和可靠性,同时也可以提供更好的用户体验,本文将介绍如何使用Spring Boot实现异步消息处理,并提供相应的代码示例
    2023-06-06
  • 新建springboot项目时,entityManagerFactory报错的解决

    新建springboot项目时,entityManagerFactory报错的解决

    这篇文章主要介绍了新建springboot项目时,entityManagerFactory报错的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • 基于SpringBoot实现用户身份验证工具

    基于SpringBoot实现用户身份验证工具

    这篇文章主要介绍了基于SpringBoot实现的用户身份验证工具,非常不错,具有参考借鉴价值 ,需要的朋友可以参考下
    2018-04-04
  • Java中的字节流文件读取教程(一)

    Java中的字节流文件读取教程(一)

    这篇文章主要给大家介绍了关于Java中字节流文件读取的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • struts2简介_动力节点Java学院整理

    struts2简介_动力节点Java学院整理

    Struts2框架是MVC流程框架,适合分层开发,这篇文章主要为大家详细介绍了struts2简介的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • MyBatisCodeHelperPro最新激活方法(有效方法)

    MyBatisCodeHelperPro最新激活方法(有效方法)

    这篇文章主要介绍了MyBatisCodeHelperPro最新激活方法亲测有效,非常好用,小编今天以idea2021.2.1为例给大家详细讲解,需要的朋友可以参考下
    2022-08-08
  • java bootclasspath的具体用法

    java bootclasspath的具体用法

    本文主要介绍了java bootclasspath的具体用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Java 深入浅出讲解代理模式

    Java 深入浅出讲解代理模式

    代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象
    2022-03-03
  • Mybatis collection查询集合属性报错的解决方案

    Mybatis collection查询集合属性报错的解决方案

    这篇文章主要介绍了Mybatis collection查询集合属性报错的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • idea 配置checkstyle详细步骤

    idea 配置checkstyle详细步骤

    checkstyle是提高代码质量,检查代码规范的很好用的一款工具,本文简单介绍一下集成的步骤,并提供一份完整的checkstyle的代码规范格式文件,以及常见的格式问题的解决方法,需要的朋友可以参考下
    2023-11-11

最新评论