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版本和获取更多知识点、面试题的朋友可以加q群:580763979 备注:简书 免费领取~
接下来从@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配置即可。
创建一个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技术文档,以及我为大家精心准备的多套简历模板(不断更新中),希望大家都能找到心仪的工作!
有需要的朋友可以加q群:580763979 备注:简书 免费领取~