• 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)配置提示功能

    如下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。

    在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,用一个工程不是更好吗,感觉牵强得很。

  • 相关阅读:
    java毕业设计基于BS架构的疫情包联信息管理系统的设计与实现mybatis+源码+调试部署+系统+数据库+lw
    CCProxy代理服务器地址的设置步骤
    从执行class文件开始认识JVM
    PushBackInputStream
    微信小程序项目源码ssm校园跑腿+后台管理系统|前后分离VUE含论文+PPT+源码
    SQL RIGHT JOIN 详解
    git常用命令等相关操作
    Redis字符串指令
    平滑加权轮询算法
    【Java 基础篇】Java LinkedHashSet 详解:有序唯一元素存储的完美选择
  • 原文地址:https://blog.csdn.net/zhangzhaokun/article/details/134252234