带你深入了解 SpringBoot 自动配置原理及自定义Starter

20 篇文章 0 订阅
19 篇文章 0 订阅

1.SpringBoot自动配置原理

从@SpringBootApplication注解开始说,这个注解是一个复合注解,他是由以下几个注解构成的。

// 用于讲其他配置类,注入到spring ioc中的
@SpringBootConfiguration
// 自动配置最重要的注解
@EnableAutoConfiguration
// 用于扫描其他注解(@service、@controller)等等
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

记得点赞收藏加关注哦 ,需要下载PDF版本和获取更多知识点、面试题的朋友可以点一点下方链接免费领取

链接:点这里!!! 580763979 暗号:CSDN

在这里插入图片描述

接下来从@EnableAutoConfiguration开始讲起

其中关键的地方就是这个AutoConfigurationImportSelector类
@Import({AutoConfigurationImportSelector.class})

他里面的selectImports方法中getAutoConfigurationEntry就是获取自动配置的重要组成

public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
    return NO_IMPORTS;
} else {
    AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
    return EMPTY_ENTRY;
} else {
    AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
    List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
    configurations = this.removeDuplicates(configurations);
    Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
    this.checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = this.getConfigurationClassFilter().filter(configurations);
    this.fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}

通过上述获取在META-INF/spring.factories,

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

在spring.factories中会存在很多这样的键值对

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

当springboot启动的时候就会加载这些xxxAutoConfigureation,这里以RedisAutoConfiguration为例,介绍是如何进行配置的。

// 只有符合这种要求的,才会将xxxAutoConfigureation加载到spring中
@ConditionalOnClass({RedisOperations.class})
// 开启配置类
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {

RedisProperties配置类,看到这个类,是不是很熟悉,他就是我们在yml里面配置的东西

@ConfigurationProperties(
    prefix = "spring.redis"
)
public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost";
    private String username;
    private String password;
    private int port = 6379;
    private boolean ssl;
    private Duration timeout;
    private Duration connectTimeout;
    private String clientName;
}

总结:通过上述流程实现将快速配置,减少了繁琐的xml配置,如果要配置,只需简单的在yml配置即可。

2.自定义starter,简单实现一个线程池的创建

创建一个thread-pool-execute-starter的工程

// 添加依赖
<groupId>com.angel.item</groupId>
<artifactId>thread-pool-execute-starter</artifactId>
<version>1.0</version>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
</dependencies>

自动配置类

@Configuration
// 配置配置属性
@EnableConfigurationProperties(ThreadPoolExecutorProperties.class)
// 只有这个类才会生校
@ConditionalOnClass(ThreadPoolExecutor.class)
public class ThreadPoolAutoConfiguration {

    /**
     * 阻塞队列
     */
    private final BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(4);
    /**
     * 拒绝策略
     */
    private final RejectedExecutionHandler reject = new ThreadPoolExecutor.AbortPolicy();
    /**
     * 线程池类型:CPU密集型:1;IO密集型:2
     */
    @Value("${scenes}")
    private Integer scenes;
    /**
     * 核心线程数大小
     */
    private Integer corePoolSize;
    /**
     * 最大线程数大小
     */
    private Integer maximumPoolSize;
    /**
     * 空闲线程存活时长
     */
    private Long keepAliveTime;
    /**
     * 存活时长单位
     */
    private TimeUnit unit;

    @PostConstruct
    public void init() {
        // 获取系统CPU核心数
        int cpuCoreNumber = Runtime.getRuntime().availableProcessors();
        this.corePoolSize = cpuCoreNumber;
        this.maximumPoolSize = 25 * cpuCoreNumber;
        this.keepAliveTime = 60 * 3L;
        this.unit = TimeUnit.SECONDS;
    }

    /**
     * N: CPU核心数
     * CPU密集型:corePoolSize = N + 1
     * IO密集型:corePoolSize = 2 * N
     */
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        // cpu密集型
        if (scenes == 1) {
            corePoolSize = corePoolSize + 1;
        } else {
            // io密集型
            corePoolSize = 2 * corePoolSize;
        }
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, reject);
    }
}

配置类属性

@ConfigurationProperties(
        prefix = "thread.pool"
)
public class ThreadPoolExecutorProperties {

    private Integer scenes = 1;

    public Integer getScenes() {
        return scenes;
    }

    public void setScenes(Integer scenes) {
        this.scenes = scenes;
    }
}

在resources中新建META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.angel.item.ThreadPoolAutoConfiguration

将工程重新打包,mvn clean install -U

在另外的工程中引入上面的坐标

<dependency>
    <groupId>com.angel.item</groupId>
    <artifactId>thread-pool-execute-starter</artifactId>
    <version>1.0</version>
</dependency>

在yml配置即可

thread:
  pool:
    scenes: 1

mvn package 重新打包

总结:通过上述配置自定义starter就可以实现了

总结

我这里也准备了一线大厂面试资料和超硬核PDF技术文档,以及我为大家精心准备的多套简历模板(不断更新中),希望大家都能找到心仪的工作!

有需要的朋友可以点一点下方链接免费领取

链接:点这里!!! 580763979 暗号:CSDN

在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值