助力SpringBoot自动配置的条件注解ConditionalOnXXX分析--SpringBoot源码(三)

2020/3/1 17:14:43

本文主要是介绍助力SpringBoot自动配置的条件注解ConditionalOnXXX分析--SpringBoot源码(三),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

注:该源码分析对应SpringBoot版本为2.1.0.RELEASE

1 前言

本篇接 如何分析SpringBoot源码模块及结构?--SpringBoot源码(二)

上一篇分析了SpringBoot源码结构及各个模块pom之间的关系后,那么此篇开始就开始解开SpringBoot新特性之一--自动配置的神秘面纱了。因为SpringBoot自动配置原理是基于其大量的条件注解ConditionalOnXXX,因此,本节我们先来撸下Spring的条件注解的相关源码。

2 SpringBoot的派生条件注解

我们都知道,SpringBoot自动配置是需要满足相应的条件才会自动配置,因此SpringBoot的自动配置大量应用了条件注解ConditionalOnXXX。如下图:

那么上图的条件注解如何使用呢?

举个栗子,我们来看下如何使用@ConditionalOnClass@ConditionalOnProperty这两个注解,先看下图代码:

HelloWorldEnableAutoConfiguration这个自动配置类应用了@ConditionalOnClassConditionalOnProperty两个条件注解,那么只有在满足:classpath中存在HelloWorldComponent.class和配置了hello.world.namehello.world.age属性这两个条件的情况下才会创建HelloWorldComponent这个bean

其实SpringBoot的@ConditionalOnXXX等条件注解都是派生注解,那么什么是派生注解呢? 就拿上面的栗子来说,以@ConditionalOnClass(HelloWorldComponent.class)为例,我们打开ConditionalOnClass注解源码,如下:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {

	Class<?>[] value() default {};

	String[] name() default {};

}
复制代码

可以看到@ConditionalOnClass注解上面又标注了@Conditional(OnClassCondition.class)注解,因此@ConditionalOnClass@Conditional的派生注解,@Conditional(OnClassCondition.class)@ConditionalOnClass注解是等价的,即这两个注解标注在某个配置类上的效果是等价的。

而SpringBoot的自动配置原理正是建立在这些大量的派生条件注解@ConditionalOnXXX之上,而这些条件注解的原理跟Spring的Condition接口有关。因此我们先来研究下Condition接口的相关源码。

3 Condition接口

3.1 Condition接口源码分析

分析Condition接口源码前先看下如何自定义ConditionalOnXXX注解,举个栗子,比如自定义一个@ConditionalOnLinux注解,该注解只有在其属性environment是"linux"才会创建相关的bean。定义了以下代码:

/**
 * 实现spring 的Condition接口,并且重写matches()方法,如果@ConditionalOnLinux的注解属性environment是linux就返回true
 *
 */
public class LinuxCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// 获得注解@ConditionalOnLinux的所有属性
		List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
				metadata.getAllAnnotationAttributes(
						ConditionalOnLinux.class.getName()));
		for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
			// 获得注解@ConditionalOnLinux的environment属性
			String environment = annotationAttributes.getString("environment");
			// 若environment等于linux,则返回true
			if ("linux".equals(environment)) {
				return true;
			}
		}
		return false;
	}
}
复制代码
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(LinuxCondition.class)
public @interface ConditionalOnLinux {
	// 标注是哪个环境
	String environment() default "";

}
复制代码
@Configuration
public class ConditionConfig {
        // 只有`@ConditionalOnLinux`的注解属性`environment`是"linux"时才会创建bean
	@Bean
	@ConditionalOnLinux(environment = "linux")
	public Environment linuxEnvironment() {
		return new
                   

这篇关于助力SpringBoot自动配置的条件注解ConditionalOnXXX分析--SpringBoot源码(三)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程