spring-boot-starter


Spring Boot的出现,得益于“习惯优于配置”的理念,没有繁琐的配置、难以集成的内容(大多数流行第三方技术都被集成),这是基于Spring 4.x提供的按条件配置Bean的能力。

Springboot自动装配

命名规范

Srping官方命名格式为:spring-boot-starter-{name}

非Spring官方建议命名格式:{name}-spring-boot-starter

Spring Boot的配置文件

Spring Boot有一个全局配置文件:application.propertiesapplication.yml

常用属性配置

工作原理剖析

Spring Boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中:

自动配置

Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot项目必不可少的注解。那么自动配置原理一定和这个注解有着千丝万缕的联系!

@EnableAutoConfiguration

SpringBootApplication

@SpringBootApplication是一个复合注解或派生注解,在@SpringBootApplication中有一个注解@EnableAutoConfiguration,翻译成人话就是开启自动配置,其定义如下:

EnableAutoConfiguration.png

而这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories 的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。

这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:

spring.factories.png

这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

自动配置生效

每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

  • @ConditionalOnBean:当容器里有指定的bean的条件下。
  • @ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
  • @ConditionalOnClass:当类路径下有指定类的条件下。
  • @ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
  • @ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)。

ServletWebServerFactoryAutoConfiguration

ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。

ServerProperties

在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。

而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。

可能到目前为止还是有所疑惑,但面试的时候,其实远远不需要回答的这么具体,你只需要这样回答:

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

开发示例

代码结构

POM引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.13</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.rrc</groupId>
    <artifactId>rrc-log-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 提供了自动装配功能-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <!-- 在编译时会自动收集配置类的条件,写到一个META-INF/spring-autoconfigure-metadata.json中-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
        <!--记录日志会用到切面,所以需要引入-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.2.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

spring-boot-autoconfigure:

提供自动化装配功能,是为了Spring Boot 应用在各个模块提供自动化配置的作用;即加入对应 pom,就会有对应配置其作用;所以我们想要自动装配功能,就需要引入这个依赖。

spring-boot-configuration-processor:

将自定义的配置类生成配置元数据,所以在引用自定义STARTER的工程的YML文件中,给自定义配置初始化时,会有属性名的提示;确保在使用@ConfigurationProperties注解时,可以优雅的读取配置信息,引入该依赖后,IDEA不会出现“spring boot configuration annotation processor not configured”的错误;编译之后会在META-INF 下生成一个
spring-configuration-metadata.json 文件,大概内容就是定义的配置的元数据;效果如下截图。

元数据

定义属性配置

package com.rrc.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "rrc")
@Data
public class LogProperties {


    /**
     * 是否开启日志
     */
    private boolean enable;


    /**
     * 平台:不同服务使用的区分,默认取 spring.application.name
     */
    @Value("${spring.application.name:#{null}}")
    private String platform;
}

@ConfigurationProperties:该注解和@Value 注解作用类似,用于获取配置文件中属性定义并绑定到Java Bean 或者属性中;换句话来说就是将配置文件中的配置封装到JAVA 实体对象,方便使用和管理。

这边我们定义两个属性,一个是是否开启日志的开关,一个是标识平台的名称。

定义自动配置类

package com.rrc;

import com.rrc.config.LogProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.rrc")
@ConditionalOnProperty(prefix = "rrc",name = "enable",havingValue = "true",matchIfMissing = false)
@EnableConfigurationProperties({LogProperties.class})
public class RrcLogAutoConfiguration {
}

这个类最关键了,它是整个starter 最重要的类,它就是将配置自动装载进spring-boot的;具体是怎么实现的,下面在讲解原理的时候会再详细说说,这里先完成示例。

引用

徒手撸一个Spring Boot中的starter,解密自动化配置

天天在用SpringBoot,手撸一个的Starter试试!

只需4步,自己搞个 Spring Boot Starter !

如何使用SpringBoot封装自己的Starter

SpringBoot 系列三 : SpringBoot 自定义 Starter

SpringBoot:认认真真梳理一遍自动装配原理

SpringBoot四大核心组件,你知道几个?


文章作者: WangQingLei
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WangQingLei !
  目录