Springboot自动配置那些事

Spring Boot中默认会扫描的启动类对应的子包下面的类,但是项目引入的其他包下面的类要加入到IOC中必须要有所说明,以下说到的自动配置就是干这个活的,springboot就会把配置中的类加载到ioc容器中。

(1)自动配置注册文件

从Spring boot2.7开始自动配置注册有了一个比较大的调整,之前都是写在下面 文件中的:

META-INF/spring.factories

格式为: org.springframework.boot.autoconfigure.EnableAutoConfiguration=[XXXConfig,YYYConfig]

自Spring Boot 2.7 起改名了:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

格式也变了,直接每一行是一个自动配置类,比如spring-cloud-netflix-eureka-client-4.0.3.jar 中的该文件内容为:

org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration

org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration

org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration

org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration

org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration

org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration

(2)新注解(@AutoConfiguration)

新增了一个自动配置注解 @AutoConfiguration,用来代替之前的 @Configuration,用于标识新自动配置注册文件中的顶级自动配置类,由 @AutoConfiguration 注解嵌套、导入进来的其他配置类可以继续使用 @Configuration 注解。

另外,为方便起见,@AutoConfiguration 注解还支持 after, afterNames, before 和 beforeNames 属性进行自动配置排序,用于代替之前的 @AutoConfigureAfter 和 @AutoConfigureBefore 注解。

@AutoConfiguration(

before = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },

after = MetricsAutoConfiguration.class)

@ConditionalOnBean(Clock.class)

@ConditionalOnClass(ElasticMeterRegistry.class)

@ConditionalOnEnabledMetricsExport("elastic")

@EnableConfigurationProperties(ElasticProperties.class)

public class ElasticMetricsExportAutoConfiguration {

}

上述@AutoConfiguration表示ElasticMetricsExportAutoConfiguration.class类的bean应该在如下类MetricsAutoConfigurationa.class的bean被创建之后才被创建,并且需要在类CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class的bean被创建之前,清楚的表明了bean被创建的先后顺序。

上述@ConditionalOnBean(Clock.class)表示存在类 Clock.class的bean才创建ElasticMetricsExportAutoConfiguration.class的bean。

上述@ConditionalOnClass(ElasticMeterRegistry.class)表示classpath中存在类ElasticMeterRegistry.class才创建ElasticMetricsExportAutoConfiguration.class的bean。

上述@ConditionalOnEnabledMetricsExport("elastic") 表示需要在引入了 elastic 并且 actuator 暴露了 elastic 端口的情况下才创建ElasticMetricsExportAutoConfiguration.class的bean。

上述@EnableConfigurationProperties(ElasticProperties.class)表示让@ConfigurationProperties 注解的类ElasticProperties.class被加载生效。

SpringBoot中常用的条件注解:

注解定义都在spring-boot-autoconfigure-x.y.z.jar的包org.springframework.boot.autoconfigure.condition中:

@ConditionalOnBean(CqlSession.class) 配置的CqlSession.class类的bean存在时,才会创建这个bean;

@ConditionalOnMissingBean 配置的bean不存在时,才会创建这个bean;

@ConditionalOnClass(RabbitTemplate.class) Classpath中存在配置的类RabbitTemplate.class,才会创建这个bean;

@ConditionalOnMissingClasses Classpath中不存在配置的类,才会创建这个bean;

@ConditionalOnJava JDK版本在范围以内,才会创建这个bean;

@ConditionalOnExpression 指定的SpEL表达式结果为true,才会创建这个bean;

@ConditionalOnWebApplication 是一个WEB应用程序,才会创建这个bean;

@ConditionalOnNotWebApplication 不是一个WEB应用程序,才会创建这个bean;

@ConditionalOnCloudPlatform 仅当我们在某个云平台上运行时才加载bean:

@ConditionalOnJndi("java:comp/env/ejb/myEJB") 仅当通过JNDI提供某个资源时才加载bean:

@ConditionalOnProperty(prefix = "management.auditevents", name = "enabled") 仅在存在环境属性(management.auditevents.enabled)且配置的值不等于false才创建bean。

@ConditionalOnProperty(prefix = "management.health.readinessstate", name = "enabled", havingValue = "true")仅在存在环境属性(management.health.readinessstate.enabled)且配置的值为true才创建bean。

@ConditionalOnResource(resources = "${spring.info.build.location:classpath:META-INF/build-info.properties}") 仅当指定的资源文件出现在classpath中才创建bean

关于@AutoConfigureBefore和@AutoConfigureAfter的用法

以下为案例:

@AutoConfigureBefore(Test1.class)

@AutoConfigureAfter(Test2.class)

public class TestConfig {

}

表示TestConfig.class应该在Test2.class加载后即自动加载,并且要在类Test1.class加载之前。

条件注解的起源:

条件注解发源自注解Conditional,该注解传入的参数是Condition。

注解:org.springframework.context.annotation.Conditional.class

@Target({ElementType.TYPE, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Conditional {

Classextends Condition>[] value();

}

接口org.springframework.context.annotation.Condition.class,是一个函数式接口:

@FunctionalInterface

public interface Condition {

boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

以条件注解@ConditionalOnBean为例来看具体的实现:

@Target({ ElementType.TYPE, ElementType.METHOD })

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Conditional(OnBeanCondition.class)

public @interface ConditionalOnBean {

Class[] value() default {};

String[] type() default {};

Classextends Annotation>[] annotation() default {};

String[] name() default {};

SearchStrategy search() default SearchStrategy.ALL;

Class[] parameterizedContainer() default {};

}

从上述代码可以看到,真正来判定Bean是否存在的条件是由类OnBeanCondition.class来完成的。

参考如下,OnBeanCondition.java 是来实现ConfigurationCondition.java接口的,ConfigurationCondition.java是继承自Condition.java 这个函数式接口,真正的判定条件匹配是在boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);方法中来实现的。

@Order(Ordered.LOWEST_PRECEDENCE)

class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {

}

Spring和Spring Boot的注解水很深,用法出神入化了。

(3)配置提示功能

Springboot自动配置那些事_第1张图片

如下3个文件都是用于配置提示:

spring-configuration-metadata.json

additional-spring-configuration-metadata.json

spring-autoconfigure-metadata.properties

其中spring-configuration-metadata.json和spring-autoconfigure-metadata.properties是插件生成的,additional-spring-configuration-metadata.json一般没额外的补充信息需求的话也不用写。

自定义配置提示只需要在项目中引入如下依赖即可:

dependency>

groupId>org.springframework.bootgroupId>

artifactId>spring-boot-autoconfigureartifactId>

dependency>

dependency>

groupId>org.springframework.bootgroupId>

artifactId>spring-boot-autoconfigure-processorartifactId>

dependency>

dependency>

groupId>org.springframework.bootgroupId>

artifactId>spring-boot-configuration-processorartifactId>

optional>trueoptional>

dependency>

(4)spring-boot-starter-xxx.jar为什么都是空项目?

以spring-cloud-starter-loadbalancer-4.0.4.jar为例,本身是一个空项目,只是依赖项目spring-cloud-loadbalancer-4.0.4.jar。

Springboot自动配置那些事_第2张图片

在spring-cloud-loadbalancer-4.0.4.jar中的关键自动配置部分:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,

给出了自动配置的信息。

之所以拆分为一个空工程和一个配置工程的原因,只能先猜测一下。

(1)有可能是空的spring-cloud-starter-xxx工程可以有比较灵活的依赖,不一定要和spring-cloud-xxx完全绑死,除了依赖spring-cloud-xxx外还可以依赖其他工程。

但是spring-boot-starter-3.1.4.jar和spring-boot-start-cache-3.1.4.jar和spring-boot-start-freemarker-3.1.4.jar 这些都是空工程,连依赖都没有,根本体现不出来上面的意义啊。

(2)也可能是有名字好理解一点

如果是这个理由,直接把spring-cloud-xxx命名为spring-cloud-starter-xxx,用一个工程不是更好吗,感觉牵强得很。

你可能感兴趣的:(SpringBoot,spring,SpringBoot)