小白都能听懂的spring boot自动化配置原理

简介: spring boot最核心的特性就是他的自动化配置特性,极大的减少了构建一个spring web工程的工作量。那么你知道spring boot自动化配置的原理吗?

先直接自定义一个user-spring-boot-starter组件,感受下自动化配置的魅力。


构建user-spring-boot-starter


pom依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.laowan</groupId>
    <artifactId>user-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>user-spring-boot-starter</name>
    <description>user-spring-boot-starter</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>


添加配置属性


spring.user.enabled=false
spring.user.name=laowan


创建UserPorperties属性类使用配置属性


@Data
@ConfigurationProperties("spring.user")
public class UserPorperties {
    private String name;
}


利用属性类UserPorperties构建UserClient对象

public class UserClient {
    private UserPorperties userPorperties;
    public UserClient(){
    }
    public UserClient(UserPorperties userPorperties){
          this.userPorperties = userPorperties;
    }
    public String getName(){
        return userPorperties.getName();
    }
}


核心:创建UserAutoConfigure自动化配置类


@Configuration
@EnableConfigurationProperties(UserPorperties.class)
public class UserAutoConfigure {
    @Bean
    @ConditionalOnProperty(prefix = "spring.user",value ="enabled",havingValue = "true")
    public UserClient userClient(UserPorperties userPorperties){
        return new UserClient(userPorperties);
    }
}


说明:

@ConfigurationProperties(“spring.user”)

读取以spring.user为前缀的属性文件,配置实体类


@EnableConfigurationProperties(UserPorperties.class)

将使用了@ConfigurationProperties 注解的类注入到spring容器中。

如果一个配置类只配置@ConfigurationProperties注解,而没有使用@Component,那么在IOC容器中是获取不到properties 配置文件转化的bean。

简单来说@EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。


@ConditionalOnProperty 属性条件判断,判断指定的属性是否有指定的值,满足条件才会初始化bean。


类似UserAutoConfigure这样的自动化配置类是所有自动化配置组件的核心入口。

我们需要的就是在引入了user-spring-boot-starter的依赖后,在spring容器启动的时候,加载到这个自动化配置类,那么就可以初始化UserClient,完成自动化配置。


加载自动化配置类的三种方式


由于Spring boot默认扫描的是跟启动类平级的包。如果我们的Start跟启动类不在同一个主包下,那么就需要通过其他手段使得容器启动加载到UserAutoConfigure自动化配置类。


方式一:创建spring.factories属性配置文件

在user-spring-boot-starter工程下的/resources/META-INF目录下创建spring.factories属性配置文件,并在里面指定自动化属性配置类的全路径。


org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.laowan.user.autoconfig.UserAutoConfigure

这是由于在spring boot开启了自动化配置注解后,在容器启动时,会自动加载所有

/resources/META-INF下的spring.factories文件,读取org.springframework.boot.autoconfigure.EnableAutoConfiguration配置属性,组成一个集合,然后去遍历加载所有的自动化配置类。


建立demo工程测试:

1、引入user-spring-boot-starter的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>com.laowan</groupId>
    <artifactId>user-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>


2、配置属性文件

spring.user.enabled=true
spring.user.name=laowan


3、编写单元测试类

@SpringBootTest
@Slf4j
class DemoApplicationTests {
    @Autowired
    UserClient userClient;
    @Test
    void userClientTest() {
        log.info(userClient.getName());
    }
}


4、执行结果

41.png

说明我们的自动化配置生效


方式二:通过定义@EnableXXX注解来加载自动化配置文件

在user-spring-boot-starter工程下,新建@EnableUserClient注解,其中最核心的是通过

@Import注解注入了UserAutoConfigure.class。这样在引用工程的启动类上只要添加了@EnableUserClient注解,那么就会加载到UserAutoConfigure自动化配置类


```javascript
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({UserAutoConfigure.class})
public @interface EnableUserClient {
}


测试:

@SpringBootApplication
@EnableUserClient
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}


先注释掉spring.factories中的配置项,然后执行单元测试,正确打印出配置属性spring.user.name的值,说明我们的自动化配置生效。


方式三:通过@SpringBootApplication注解指定扫描的基础包路径


在测试工程demo中,配置@SpringBootApplication的属性scanBasePackages

@SpringBootApplication(scanBasePackages = {"com.laowan.demo","com.laowan.user.autoconfig"})
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}


通过@SpringBootApplication注解的scanBasePackages 属性,指定扫描的包路径。

这里注意,一定要首先指定自己工程的根路径,然后再执行自动化配置类的包路径。

不然就只会扫描自动化配置类的包路径,自己工程就不会扫描导致启动出错。


测试:

执行单元测试,发现配置属性spring.user.name的值仍然可以正常打印,说明我们的自动化配置成功。


三种方式的比较:

三种加载自动化配置的方式,其核心都是解决Spring boot工程启动只会默认扫描跟启动类平级的包,导致其他不同包下的自动化配置类XXXAutoConfigure.class加载不到的问题。

方式一是通过spring.factories文件中配置org.springframework.boot.autoconfigure.EnableAutoConfiguration属性指定自动化配置类XXXAutoConfigure.class的全路径,是最主流的方式。

方式二通过自定义@EnableXXX注解并结合@Import注解加载自动化配置文件,在很多组件中也很常见,比如:


@EnableResourceServer

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ResourceServerConfiguration.class})
public @interface EnableResourceServer {
}


@EnableDiscoveryClient

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableDiscoveryClientImportSelector.class})
public @interface EnableDiscoveryClient {
    boolean autoRegister() default true;
}


方式三主要是对自动化配置原理的一种验证,实际项目中不推荐。


自动化配置原理核心:

就是想办法在spring容器启动的时候,扫描到自动化配置类,然后根据属性类和条件注解去声明Bean,完成自动化配置。


实现配置项提示功能


在user-spring-boot-starter工程的/resources/META-INF目录下创建spring-configuration-metadata.json

{
  "properties": [
    { "name": "spring.user.name",
      "defaultValue": "laowan",
      "description": "用户名称.",
      "type": "java.lang.String"
    },
    { "name": "spring.user.enabled",
      "defaultValue": false,
      "description": "是否启用user组件.",
      "type": "java.lang.Boolean"
    }
  ]
}


这样在引用工程中配置相关属性,就会出现提示了。

40.png


通用规定


1、spring官方自己定义的starter组件,命名规则:spring-boot-starter-组件名

如:

spring-boot-starter-web

spring-boot-starter-jdbc

spring-boot-starter-security


非官方定义的start组件,命名规则:组件名-spring-boot-starter

如:

mybatis-spring-boot-starter


2、自动化配置类命名:XXXAutoConfiguration


3、starter组件的常规目录结构分析

一般分为2个工程,一个xxx-spring-boot-starter工程,通过spring.provides指定依赖服务模块;

一个xxx-spring-boot-starter-autoconfigure模块,通过定义spring.factories指定自动化配置文件加载路径,定义spring-configuration-metadata.json实现自动化配置。

39.png


核心注解


在构建starter的过程中,涉及到一些注解

@EnableAutoConfiguration 开启自动化配置功能,包含在@SpringBootApplication注解中,可以通过exclude属性,过滤掉一些不需要开启自动化配置的组件。


@Import 通过快速导入的方式实现把实例加入spring的IOC容器中,@Import只能用在类上


@ConfigurationProperties(“spring.user”) 加载前缀为spring.user的属性去配置当前类,但是并不会加载到spring容器中,需要配合@Component或者@EnableConfigurationProperties去使用。

@EnableConfigurationProperties(UserPorperties.class) 使 使用了@ConfigurationProperties注解配置的类生效,也就是注入到spring容器中


条件注解@Conditional

可以放在加了@Configuration的配置类上面,也可以放在使用@Bean定义bean的时候。用来判断是否开启配置或是否注入bean。

@ConditionalOnBean:当容器中有指定的Bean的条件下

@ConditionalOnClass:当类路径下有指定的类的条件下

@ConditionalOnExpression:基于SpEL表达式作为判断条件

@ConditionalOnJava:基于JVM版本作为判断条件

@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置

@ConditionalOnMissingBean:当容器中没有指定Bean的情况下

@ConditionalOnMissingClass:当类路径下没有指定的类的条件下

@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下

@ConditionalOnProperty:指定的属性是否有指定的值

@ConditionalOnResource:类路径下是否有指定的资源

@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean

@ConditionalOnWebApplication:当前项目是Web项目的条件下


总结


1、自动化配置的原理:

(1)、加载自动化配置类

通过@EnableAutoConfiguration开启自动化配置机制,原理是通过类加载器去扫描目录下所有spring.factories文件,读取org.springframework.boot.autoconfigure.EnableAutoConfiguration属性,然后去加载XXXAutoConfigure自动化配置类。这个是通用的加载方式,适合批量默认自动开启的组件。


针对某些特定组件,没有定义spring.factories文件,则需要通过在启动类上添加@EnableXXX的注解,通过@Import导入指定的自动化配置类,这种方式适合单一控制,默认不开启自动化配置的组件。


(2)、根据读取到的自动化配置类,完成相关配置过程

XXXAutoConfigure自动化配置类中根据spring boot相关注解,读取相关属性文件,并根据@Conditional条件注解判断是否开启自动化配置,是否实例化Bean。


2、自动化配置类加载的三种方式


3、怎么自定义一个starter组件以及相关的规范


4、自动化配置过程中,常见注解的说明


实战代码Git地址:https://github.com/StarlightWANLI/auto-config.git

目录
相关文章
|
4月前
|
人工智能 Ubuntu 前端开发
Dify部署全栈指南:AI从Ubuntu配置到HTTPS自动化的10倍秘籍
本文档介绍如何部署Dify后端服务及前端界面,涵盖系统环境要求、依赖安装、代码拉取、环境变量配置、服务启动、数据库管理及常见问题解决方案,适用于开发与生产环境部署。
1023 1
|
4月前
|
缓存 Java 开发者
【Spring】原理:Bean的作用域与生命周期
本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。
620 22
|
4月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
1745 0
|
6月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1105 0
|
3月前
|
监控 Java BI
《深入理解Spring》定时任务——自动化调度的时间管理者
Spring定时任务通过@Scheduled注解和Cron表达式实现灵活调度,支持固定频率、延迟执行及动态配置,结合线程池与异常处理可提升可靠性,适用于报表生成、健康检查等场景,助力企业级应用自动化。
|
3月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
3月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
412 3
|
3月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
510 2
|
4月前
|
Java 测试技术 数据安全/隐私保护
通过yaml文件配置自动化测试程序
通过yaml文件可以将自动化测试环境,测试数据和测试行为分开,请看一下案例
151 4
|
4月前
|
jenkins Java 持续交付
使用 Jenkins 和 Spring Cloud 自动化微服务部署
随着单体应用逐渐被微服务架构取代,企业对快速发布、可扩展性和高可用性的需求日益增长。Jenkins 作为领先的持续集成与部署工具,结合 Spring Cloud 提供的云原生解决方案,能够有效简化微服务的开发、测试与部署流程。本文介绍了如何通过 Jenkins 实现微服务的自动化构建与部署,并结合 Spring Cloud 的配置管理、服务发现等功能,打造高效、稳定的微服务交付流程。
628 0
使用 Jenkins 和 Spring Cloud 自动化微服务部署