SpringBoot自动配置源码详解及自定义starter代码编写

一、源码跟踪

1.首先我们知道SpringBoot的核心注解@SpringBootApplication包含@SpringBootConfiguration
、@EnableAutoConfiguration、@ComponentScan
其中@EnableAutoConfiguration是实现自动配置的核心。
点进@EnableAutoConfiguration,代码如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

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

    String[] excludeName() default {};
}

可以看到核心注解为
@Import({AutoConfigurationImportSelector.class})

2.AutoConfigurationImportSelector.class
点进{AutoConfigurationImportSelector.class,可以看到在这里插入图片描述
接下来主要围绕着loadMetadata和getAutoConfigurationEntry展开

3.loadMetadata和getAutoConfigurationEntry
(1)进入loadMetadata,可以看到主要是读取配置文件META-INF/spring-autoconfigure-metadata.properties,把里面的数据放到AutoConfigurationMetadata对象中,这个对象怎么用的呢,我们接着往下看。
在这里插入图片描述
(2)搜索AutoConfigurationMetadata对象,首先在getAutoConfigurationEntry方法中调用,最终在filter方法中使用,filter里面传入的两个参数,另一个参数来自getAutoConfigurationEntry的getCandidateConfigurations
在这里插入图片描述
(3)getCandidateConfigurations
点进getCandidateConfigurations,可以看到最终也是返回一个配置,这个配置来自哪个文件我们从提示大概能猜到是META-INF/spring.factories
在这里插入图片描述
(4)loadFactoryNames
点进loadFactoryNames,发现果然是META-INF/spring.factories
在这里插入图片描述
(5)filter
了解了所有参数之后,我们可以开始看filter了,从名字就能猜到这个方法的作用–过滤器,它过滤了什么呢,接着往下看,可以看到,用AutoConfigurationMetadata和configuration匹配,匹配不上AutoConfigurationMetadata的数据会被过滤掉,具体匹配逻辑现在还不知道,后面会解释
在这里插入图片描述
(6)autoconfigure-metadata.properties和spring.factories
①现在我们知道filter的参数主要来自两个文件autoconfigure-metadata.properties和spring.factories
,在autoconfigure的jar包下找到了这俩文件
在这里插入图片描述
②打开看看,这是autoconfigure-metadata.properties,可以看到里面有些常见的注解,这些是SpringBoot特有的条件注解
在这里插入图片描述
③然后我们再看看spring.factories,存储了很多键值对,org.springframework.boot.autoconfigure.EnableAutoConfiguration这里存了很多逗号隔开的值
在这里插入图片描述
(7)filter匹配
①关于匹配逻辑这一块,一开始我没看懂,于是打了个断点,挑了几个例子
在这里插入图片描述
在这里插入图片描述
SpringApplicationAdminJmxAutoConfiguration、AopAutoConfiguration、BatchAutoConfiguration匹配结果分别是true、true、false
②比如spring.factories中的org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
在这里插入图片描述
在autoconfigure-metadata.properties中搜索,结果如下:
在这里插入图片描述
SpringApplicationAdminJmxAutoConfiguration有两个匹配项,一个带AutoConfigureAfter且后面跟了值,一个不带;
AopAutoConfiguration在autoconfigure-metadata.properties搜不到;
BatchAutoConfiguration有两个匹配项,一个带ConditionalOnBean且后面跟了值,一个不带;
最终只有BatchAutoConfiguration被过滤了
!也就是说匹配的上的也只有部分会被过滤掉。
然后我又跟了下代码,进入OnClassCondition.class有这么一个方法,里面对ConditionalOnBean的类进行了过滤,当ConditionalOnBean后面跟的值,比如BatchAutoConfiguration.ConditionalOnBean = A
,当A不存在时,最终BatchAutoConfiguration不会被自动装配,会被过滤掉。
在这里插入图片描述

二、自定义spring-boot-starter自动配置

最早没打算做这个的,因为发现部分源码还没理解的很清楚,所以决定自己写一个试试。
1.创建一个自定义starter启动器
new一个maven项目,根据starter的命名规范最好是xxx-spring-boot-starter,我这个叫demo-spring-boot-starter
2.项目目录结构如下
在这里插入图片描述
3.pom文件配置
加入如下配置,可以使用@Configuration等注解

 <dependencies>
        <!--自定义自动装配-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.1.5.RELEASE</version>
        </dependency>
    </dependencies>

4.spring.factories
按照项目目录创建文件,加入下面代码

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.starter.configuration.AutoTestConfiguration

5.AutoTestProperties.java和AutoTestConfiguration.java

package com.starter.configuration;

import com.starter.dao.HealthCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//@Configuration相当于xml中的<beans>标签,注入容器
@Configuration
@EnableConfigurationProperties(value = AutoTestProperties.class)
public class AutoTestConfiguration {

    @Autowired
    private AutoTestProperties autoTestProperties;


    //@Bean相当于xml中的<bean>标签,注册并管理bean的生命周期
    @Bean
    public HealthCode autowired(){
        HealthCode healthCode = new HealthCode();
        healthCode.setHealthStatus(autoTestProperties.getHealthStatus());
        healthCode.setIdCard(autoTestProperties.getIdCard());
        healthCode.setUsername(autoTestProperties.getUsername());
        System.out.println("自动配置成功");
        return healthCode;
    }
}
package com.starter.configuration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;


//prefix在application.yml中使用,用来区分变量值
@ConfigurationProperties(prefix = "healthcode")
public class AutoTestProperties {
    private String username;
    private String idCard;
    private String healthStatus;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getHealthStatus() {
        return healthStatus;
    }

    public void setHealthStatus(String healthStatus) {
        this.healthStatus = healthStatus;
    }
}

6.HealthCode.java

package com.starter.dao;

public class HealthCode {
    private String username;
    private String idCard;
    private String healthStatus;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getHealthStatus() {
        return healthStatus;
    }

    public void setHealthStatus(String healthStatus) {
        this.healthStatus = healthStatus;
    }
}

7.将sarter项目打包,install即可
在这里插入图片描述
8.将starter引入已有的web项目中,在pom文件中加入下面代码,并更新一下maven

 <!--自定义starter-->
        <dependency>
            <!--grougId这几个参数直接从starter中复制过来即可-->
            <groupId>org.example</groupId>
            <artifactId>demo-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

9.在application.yml文件中加入下面配置,注意前面不要有空格

# 自定义starter配置
healthcode.username: caocao
healthcode.idCard: 362302198001013366
healthcode.healthStatus: 1

10.新建一个controller作为入口测试

package com.example.springb_web.controller;

import com.starter.dao.HealthCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController {

    @Autowired
    private HealthCode healthCode;

    @RequestMapping(value="/autoTest")
    @ResponseBody
    public HealthCode autoTest(){
        return healthCode;
    }

}

11.编译启动项目,测试
测试网址:http://localhost:8080/autoTest
12.结果如下
在这里插入图片描述

三、总结

SpringBoot的自动配置使用@EnableAutoConfiguration注释实现,是通过找到spring.factories配置文件中的所有XXXAutoConfiguration的自动配置类,并将autoconfigure-metadata.properties中含@ConditionalOnClass@AutoConfigureAfter的配置类过滤掉,然后通过@bean注册,@Configuration加载到容器,实现这些类的自动配置。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值