Merge remote-tracking branch 'origin/master'

pull/49/head
AmyliaY 5 years ago
commit 11376a3c23

@ -68,6 +68,10 @@
### SpringBoot
- [SpringBoot run方法解析](/docs/SpringBoot/Spring-Boot-Run.md)
- [SpringBoot 配置加载解析](/docs/SpringBoot/SpringBoot-application-load.md)
- [SpringBoot 自动装配](/docs/SpringBoot/SpringBoot-自动装配.md)
- [SpringBoot ConfigurationProperties](/docs/SpringBoot/SpringBoot-ConfigurationProperties.md)
- [SpringBoot 日志系统](/docs/SpringBoot/SpringBoot-LogSystem.md)
## MyBatis

@ -0,0 +1,598 @@
# SpringBoot ConfigurationProperties
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring-boot](https://github.com/SourceHot/spring-boot-read)
- 本文主要对`org.springframework.boot.context.properties.ConfigurationProperties`进行分析
## ConfigurationProperties
- 顶部注释
```java
* @see ConfigurationPropertiesScan
* @see ConstructorBinding
* @see ConfigurationPropertiesBindingPostProcessor
* @see EnableConfigurationProperties
```
看到`ConfigurationPropertiesScan` 去看看这个
## ConfigurationPropertiesScan
```JAVA
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ConfigurationPropertiesScanRegistrar.class)
@EnableConfigurationProperties
public @interface ConfigurationPropertiesScan {}
```
- 熟悉的**Import**注解
## ConfigurationPropertiesScanRegistrar
![image-20200323094446756](/images/SpringBoot/image-20200323094446756.png)
- debug没有抓到后续补充
## EnableConfigurationProperties
```JAVA
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {
}
```
## EnableConfigurationPropertiesRegistrar
- 该类会读取**spring.factories**
- 中`org.springframework.boot.autoconfigure.EnableAutoConfiguration=\` 这样的
```
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfiguration
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
```
```java
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 注册bean
registerInfrastructureBeans(registry);
// 配置属性Bean注册器
ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
// 循环注册
getTypes(metadata).forEach(beanRegistrar::register);
}
```
### registerInfrastructureBeans
```JAVA
static void registerInfrastructureBeans(BeanDefinitionRegistry registry) {
// 属性绑定后置处理器
ConfigurationPropertiesBindingPostProcessor.register(registry);
// 属性校验器
ConfigurationPropertiesBeanDefinitionValidator.register(registry);
ConfigurationBeanFactoryMetadata.register(registry);
}
```
- 此处操作逻辑基本相同,是否存在这个beanName 存在直接注册,不存在补充
#### ConfigurationPropertiesBindingPostProcessor.register(registry)
```JAVA
public static void register(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "Registry must not be null");
// 是否存在
if (!registry.containsBeanDefinition(BEAN_NAME)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationPropertiesBindingPostProcessor.class);
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, definition);
}
ConfigurationPropertiesBinder.register(registry);
}
```
#### ConfigurationPropertiesBeanDefinitionValidator.register(registry)
```JAVA
static void register(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "Registry must not be null");
if (!registry.containsBeanDefinition(BEAN_NAME)) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(ConfigurationPropertiesBeanDefinitionValidator.class);
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, definition);
}
ConfigurationPropertiesBinder.register(registry);
}
```
### getTypes(metadata).forEach(beanRegistrar::register)
- 先看输入参数 **metadata**
![image-20200323134135926](/images/SpringBoot/image-20200323134135926.png)
- getTypes结果
![image-20200323134325955](/images/SpringBoot/image-20200323134325955.png)
- 源码开始,先找出刚才的对象`org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration`
```JAVA
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {}
```
```JAVA
/**
* 找出 {@link EnableConfigurationProperties} 注解标记的中的属性值,并且返回值不是void
* @param metadata
* @return
*/
private Set<Class<?>> getTypes(AnnotationMetadata metadata) {
return
metadata.getAnnotations().stream(EnableConfigurationProperties.class)
.flatMap((annotation) -> Arrays.stream(annotation.getClassArray(MergedAnnotation.VALUE)))
.filter((type) -> void.class != type).collect(Collectors.toSet());
}
```
- 这里我们可以直接知道返回的是`@EnableConfigurationProperties(ServerProperties.class)` 的数据值: `ServerProperties.class`
循环注册
```java
void register(Class<?> type) {
MergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations
.from(type, SearchStrategy.TYPE_HIERARCHY).get(ConfigurationProperties.class);
register(type, annotation);
}
```
---
## ConfigurationPropertiesBindingPostProcessor
![image-20200323095626953](/images/SpringBoot/image-20200323095626953.png)
### postProcessBeforeInitialization
```JAVA
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 绑定
bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
return bean;
}
```
- get
```java
public static ConfigurationPropertiesBean get(ApplicationContext applicationContext, Object bean, String beanName) {
// 寻找工厂方法
Method factoryMethod = findFactoryMethod(applicationContext, beanName);
// 创建 ConfigurationPropertiesBean
return create(beanName, bean, bean.getClass(), factoryMethod);
}
```
```java
private static Method findFactoryMethod(ConfigurableListableBeanFactory beanFactory, String beanName) {
// 判断是否存在这个beanName
if (beanFactory.containsBeanDefinition(beanName)) {
// 获取bean定义
BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
// 类型判断
if (beanDefinition instanceof RootBeanDefinition) {
// 解析方法
Method resolvedFactoryMethod = ((RootBeanDefinition) beanDefinition).getResolvedFactoryMethod();
if (resolvedFactoryMethod != null) {
return resolvedFactoryMethod;
}
}
return findFactoryMethodUsingReflection(beanFactory, beanDefinition);
}
return null;
}
```
```java
private static Method findFactoryMethodUsingReflection(ConfigurableListableBeanFactory beanFactory,
BeanDefinition beanDefinition) {
// 工厂方法
String factoryMethodName = beanDefinition.getFactoryMethodName();
// 工厂bean
String factoryBeanName = beanDefinition.getFactoryBeanName();
if (factoryMethodName == null || factoryBeanName == null) {
return null;
}
// 转换对象
Class<?> factoryType = beanFactory.getType(factoryBeanName);
if (factoryType.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
factoryType = factoryType.getSuperclass();
}
AtomicReference<Method> factoryMethod = new AtomicReference<>();
ReflectionUtils.doWithMethods(factoryType, (method) -> {
// 判断是否是需要的方法
if (method.getName().equals(factoryMethodName)) {
// 设置方法
factoryMethod.set(method);
}
});
// 返回方法
return factoryMethod.get();
}
```
### create
- `org.springframework.boot.context.properties.ConfigurationPropertiesBean#create`
```JAVA
private static ConfigurationPropertiesBean create(String name, Object instance, Class<?> type, Method factory) {
// 找注解
ConfigurationProperties annotation = findAnnotation(instance, type, factory, ConfigurationProperties.class);
if (annotation == null) {
return null;
}
// 找注解
Validated validated = findAnnotation(instance, type, factory, Validated.class);
// 注解列表
Annotation[] annotations = (validated != null) ? new Annotation[] { annotation, validated }
: new Annotation[] { annotation };
// 类型解析
ResolvableType bindType = (factory != null) ? ResolvableType.forMethodReturnType(factory)
: ResolvableType.forClass(type);
// 绑定结果对象
Bindable<Object> bindTarget = Bindable.of(bindType).withAnnotations(annotations);
if (instance != null) {
bindTarget = bindTarget.withExistingValue(instance);
}
return new ConfigurationPropertiesBean(name, instance, annotation, bindTarget);
}
```
- 第一个需要做的类: `org.springframework.boot.autoconfigure.web.ServerProperties`
- `annotation`
![image-20200323104711545](/images/SpringBoot/image-20200323104711545.png)
- `bindType`
![image-20200323104815305](/images/SpringBoot/image-20200323104815305.png)
- 返回对象
![image-20200323105053757](/images/SpringBoot/image-20200323105053757.png)
- 此时数据还没有进去
#### bind
- 数据绑定
直接看结果
![image-20200323105155998](/images/SpringBoot/image-20200323105155998.png)
- 上述配置和我在配置文件中写的配置一致
```yml
server:
port: 9999
```
- 具体方法: `org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#bind`
```java
private void bind(ConfigurationPropertiesBean bean) {
if (bean == null || hasBoundValueObject(bean.getName())) {
return;
}
Assert.state(bean.getBindMethod() == BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '"
+ bean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean");
try {
// 最终的绑定
this.binder.bind(bean);
}
catch (Exception ex) {
throw new ConfigurationPropertiesBindException(bean, ex);
}
}
```
```java
BindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {
// 最后的结果
Bindable<?> target = propertiesBean.asBindTarget();
// 注解获取
ConfigurationProperties annotation = propertiesBean.getAnnotation();
// 获取处理器
BindHandler bindHandler = getBindHandler(target, annotation);
//
return getBinder().bind(annotation.prefix(), target, bindHandler);
}
```
![image-20200323105830138](/images/SpringBoot/image-20200323105830138.png)
##### findProperty
```JAVA
private ConfigurationProperty findProperty(ConfigurationPropertyName name, Context context) {
if (name.isEmpty()) {
return null;
}
for (ConfigurationPropertySource source : context.getSources()) {
// 获取具体的一个属性值
ConfigurationProperty property = source.getConfigurationProperty(name);
if (property != null) {
return property;
}
}
return null;
}
```
- `org.springframework.boot.context.properties.source.SpringConfigurationPropertySource#getConfigurationProperty`
```JAVA
@Override
public ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {
PropertyMapping[] mappings = getMapper().map(name);
return find(mappings, name);
}
```
```JAVA
protected final ConfigurationProperty find(PropertyMapping[] mappings, ConfigurationPropertyName name) {
for (PropertyMapping candidate : mappings) {
if (candidate.isApplicable(name)) {
ConfigurationProperty result = find(candidate);
if (result != null) {
return result;
}
}
}
return null;
}
```
```JAVA
private ConfigurationProperty find(PropertyMapping mapping) {
// 需要读取的配置信息的key
String propertySourceName = mapping.getPropertySourceName();
// 信息的value
Object value = getPropertySource().getProperty(propertySourceName);
if (value == null) {
return null;
}
// 创建对象
ConfigurationPropertyName configurationPropertyName = mapping.getConfigurationPropertyName();
Origin origin = PropertySourceOrigin.get(this.propertySource, propertySourceName);
// 包装返回
return ConfigurationProperty.of(configurationPropertyName, value, origin);
}
```
![image-20200323115408877](/images/SpringBoot/image-20200323115408877.png)
![image-20200323115701118](/images/SpringBoot/image-20200323115701118.png)
![image-20200323115711826](/images/SpringBoot/image-20200323115711826.png)
##### getBindHandler
```java
private <T> BindHandler getBindHandler(Bindable<T> target, ConfigurationProperties annotation) {
// 获取校验接口列表
List<Validator> validators = getValidators(target);
// 处理器
BindHandler handler = new IgnoreTopLevelConverterNotFoundBindHandler();
if (annotation.ignoreInvalidFields()) {
// 忽略错误的绑定处理器
handler = new IgnoreErrorsBindHandler(handler);
}
if (!annotation.ignoreUnknownFields()) {
UnboundElementsSourceFilter filter = new UnboundElementsSourceFilter();
// 未绑定元素处理器
handler = new NoUnboundElementsBindHandler(handler, filter);
}
if (!validators.isEmpty()) {
// 校验绑定处理器
handler = new ValidationBindHandler(handler, validators.toArray(new Validator[0]));
}
for (ConfigurationPropertiesBindHandlerAdvisor advisor : getBindHandlerAdvisors()) {
// handler
handler = advisor.apply(handler);
}
return handler;
}
```
- 最终获取得到的处理器
![image-20200323110603959](/images/SpringBoot/image-20200323110603959.png)
- 最后的bind
```java
private <T> Object bindObject(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,
Context context, boolean allowRecursiveBinding) {
// 获取属性
ConfigurationProperty property = findProperty(name, context);
if (property == null && containsNoDescendantOf(context.getSources(), name) && context.depth != 0) {
return null;
}
AggregateBinder<?> aggregateBinder = getAggregateBinder(target, context);
if (aggregateBinder != null) {
return bindAggregate(name, target, handler, context, aggregateBinder);
}
if (property != null) {
try {
return bindProperty(target, context, property);
}
catch (ConverterNotFoundException ex) {
// We might still be able to bind it using the recursive binders
Object instance = bindDataObject(name, target, handler, context, allowRecursiveBinding);
if (instance != null) {
return instance;
}
throw ex;
}
}
return bindDataObject(name, target, handler, context, allowRecursiveBinding);
}
```
![image-20200323112945449](/images/SpringBoot/image-20200323112945449.png)
配置信息到此绑定成功,关于如何处理集合相关的配置请各位读者自行学习
----

@ -0,0 +1,511 @@
# SpringBoot 日志系统
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring-boot](https://github.com/SourceHot/spring-boot-read)
- 包路径: `org.springframework.boot.logging`
## 日志级别
- 日志级别: `org.springframework.boot.logging.LogLevel`
```java
public enum LogLevel {
TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
}
```
## java 日志实现
- `org.springframework.boot.logging.java.JavaLoggingSystem`
![image-20200323144523848](/images/SpringBoot/image-20200323144523848.png)
```JAVA
static {
// KEY : springBoot 定义的日志级别, value: jdk 定义的日志级别
LEVELS.map(LogLevel.TRACE, Level.FINEST);
LEVELS.map(LogLevel.DEBUG, Level.FINE);
LEVELS.map(LogLevel.INFO, Level.INFO);
LEVELS.map(LogLevel.WARN, Level.WARNING);
LEVELS.map(LogLevel.ERROR, Level.SEVERE);
LEVELS.map(LogLevel.FATAL, Level.SEVERE);
LEVELS.map(LogLevel.OFF, Level.OFF);
}
```
- LEVELS 对象
```java
protected static class LogLevels<T> {
/**
* key SpringBoot 中定义的日志级别, value: 其他日志框架的日志级别
*/
private final Map<LogLevel, T> systemToNative;
/**
* key : 其他日志框架的日志级别 , value: springBoot 中定义中定义的日志级别
*/
private final Map<T, LogLevel> nativeToSystem;
}
```
## LoggingSystem
- 抽象类
- `org.springframework.boot.logging.LoggingSystem`
- 一个map对象: `SYSTEMS`
```JAVA
/**
* key: 第三方日志框架的类 value: springBoot 中的处理类
*/
private static final Map<String, String> SYSTEMS;
static {
Map<String, String> systems = new LinkedHashMap<>();
systems.put("ch.qos.logback.core.Appender", "org.springframework.boot.logging.logback.LogbackLoggingSystem");
systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory",
"org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");
systems.put("java.util.logging.LogManager", "org.springframework.boot.logging.java.JavaLoggingSystem");
SYSTEMS = Collections.unmodifiableMap(systems);
}
```
- 各个抽象方法
| 方法名称 | 作用 |
| ----------------------- | ---------------------------------- |
| beforeInitialize | 初始化之前调用,目的是减少日志输出 |
| initialize | 初始化日志 |
| cleanUp | 清除日志 |
| getShutdownHandler | |
| getSupportedLogLevels | 获取支持的日志级别 |
| setLogLevel | 设置日志级别 |
| getLoggerConfigurations | 获取日志配置 |
### get
```java
public static LoggingSystem get(ClassLoader classLoader) {
// 获取系统属性
String loggingSystem = System.getProperty(SYSTEM_PROPERTY);
if (StringUtils.hasLength(loggingSystem)) {
// 是不是NONE
if (NONE.equals(loggingSystem)) {
// 空的日志系统
return new NoOpLoggingSystem();
}
return get(classLoader, loggingSystem);
}
// 循环所有日志,
return SYSTEMS.entrySet().stream().filter((entry) -> ClassUtils.isPresent(entry.getKey(), classLoader))
.map((entry) ->
// 实例化具体日志
get(classLoader, entry.getValue())).findFirst()
.orElseThrow(() -> new IllegalStateException("No suitable logging system located"));
}
```
- 实例化日志系统
```java
private static LoggingSystem get(ClassLoader classLoader, String loggingSystemClass) {
try {
Class<?> systemClass = ClassUtils.forName(loggingSystemClass, classLoader);
Constructor<?> constructor = systemClass.getDeclaredConstructor(ClassLoader.class);
constructor.setAccessible(true);
return (LoggingSystem) constructor.newInstance(classLoader);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
```
![image-20200323151409473](/images/SpringBoot/image-20200323151409473.png)
- 默认日志: `org.springframework.boot.logging.logback.LogbackLoggingSystem`
### beforeInitialize
- 初始化之前
![image-20200323154205484](/images/SpringBoot/image-20200323154205484.png)
- 链路
1. `org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationEvent`
2. `org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationStartingEvent`
3. `org.springframework.boot.logging.LoggingSystem#beforeInitialize`
- 因为前文中我们已知对象是:`org.springframework.boot.logging.logback.LogbackLoggingSystem` 直接看这个类的**`beforeInitialize`**方法
```JAVA
@Override
public void beforeInitialize() {
// 日志上下文
LoggerContext loggerContext = getLoggerContext();
// 是否初始化
if (isAlreadyInitialized(loggerContext)) {
return;
}
// 父类方法
super.beforeInitialize();
// 添加过滤器
loggerContext.getTurboFilterList().add(FILTER);
}
```
- 初始化之前的的操作完成了初始化方法开始
### initialize
- `org.springframework.boot.context.logging.LoggingApplicationListener#onApplicationEnvironmentPreparedEvent`
```JAVA
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
if (this.loggingSystem == null) {
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
}
initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
}
```
- `org.springframework.boot.context.logging.LoggingApplicationListener#initializeSystem`
```JAVA
protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
new LoggingSystemProperties(environment).apply();
this.logFile = LogFile.get(environment);
if (this.logFile != null) {
this.logFile.applyToSystemProperties();
}
this.loggerGroups = new LoggerGroups(DEFAULT_GROUP_LOGGERS);
// 早期 的日志级别
initializeEarlyLoggingLevel(environment);
// 初始化日志系统
initializeSystem(environment, this.loggingSystem, this.logFile);
// 初始化日志级别
initializeFinalLoggingLevels(environment, this.loggingSystem);
registerShutdownHookIfNecessary(environment, this.loggingSystem);
}
```
```JAVA
private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system, LogFile logFile) {
LoggingInitializationContext initializationContext = new LoggingInitializationContext(environment);
String logConfig = environment.getProperty(CONFIG_PROPERTY);
if (ignoreLogConfig(logConfig)) {
// 日志系统初始化
system.initialize(initializationContext, null, logFile);
}
else {
try {
ResourceUtils.getURL(logConfig).openStream().close();
system.initialize(initializationContext, logConfig, logFile);
}
catch (Exception ex) {
// NOTE: We can't use the logger here to report the problem
System.err.println("Logging system failed to initialize using configuration from '" + logConfig + "'");
ex.printStackTrace(System.err);
throw new IllegalStateException(ex);
}
}
}
```
- `org.springframework.boot.logging.logback.LogbackLoggingSystem#initialize`
```java
@Override
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
LoggerContext loggerContext = getLoggerContext();
if (isAlreadyInitialized(loggerContext)) {
return;
}
// 日志初始化
super.initialize(initializationContext, configLocation, logFile);
loggerContext.getTurboFilterList().remove(FILTER);
markAsInitialized(loggerContext);
if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) {
getLogger(LogbackLoggingSystem.class.getName()).warn("Ignoring '" + CONFIGURATION_FILE_PROPERTY
+ "' system property. Please use 'logging.config' instead.");
}
}
```
- `org.springframework.boot.logging.AbstractLoggingSystem#initializeWithConventions`
```JAVA
private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {
String config = getSelfInitializationConfig();
if (config != null && logFile == null) {
// self initialization has occurred, reinitialize in case of property changes
reinitialize(initializationContext);
return;
}
if (config == null) {
config = getSpringInitializationConfig();
}
if (config != null) {
loadConfiguration(initializationContext, config, logFile);
return;
}
// 加载默认配置
loadDefaults(initializationContext, logFile);
}
```
- `org.springframework.boot.logging.logback.LogbackLoggingSystem#loadDefaults`
```JAVA
@Override
protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) {
LoggerContext context = getLoggerContext();
stopAndReset(context);
boolean debug = Boolean.getBoolean("logback.debug");
if (debug) {
StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
}
LogbackConfigurator configurator = debug ? new DebugLogbackConfigurator(context)
: new LogbackConfigurator(context);
Environment environment = initializationContext.getEnvironment();
context.putProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN,
environment.resolvePlaceholders("${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}"));
context.putProperty(LoggingSystemProperties.LOG_DATEFORMAT_PATTERN, environment.resolvePlaceholders(
"${logging.pattern.dateformat:${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}"));
context.putProperty(LoggingSystemProperties.ROLLING_FILE_NAME_PATTERN, environment
.resolvePlaceholders("${logging.pattern.rolling-file-name:${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}"));
new DefaultLogbackConfiguration(initializationContext, logFile).apply(configurator);
context.setPackagingDataEnabled(true);
}
```
```JAVA
@Override
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
LoggerContext loggerContext = getLoggerContext();
// 是否加载过
if (isAlreadyInitialized(loggerContext)) {
return;
}
// 日志初始化
super.initialize(initializationContext, configLocation, logFile);
// 删除 FILTER
loggerContext.getTurboFilterList().remove(FILTER);
// 初始化标记
markAsInitialized(loggerContext);
if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) {
getLogger(LogbackLoggingSystem.class.getName()).warn("Ignoring '" + CONFIGURATION_FILE_PROPERTY
+ "' system property. Please use 'logging.config' instead.");
}
}
```
标记`markAsInitialized`
```JAVA
private void markAsInitialized(LoggerContext loggerContext) {
loggerContext.putObject(LoggingSystem.class.getName(), new Object());
}
```
此时日志初始化完成
### 默认配置文件
- `getStandardConfigLocations` 这个方法定义了默认配置文件有哪些
```java
@Override
protected String[] getStandardConfigLocations() {
return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" };
}
```
- 切回`org.springframework.boot.logging.AbstractLoggingSystem#initializeWithConventions`方法
- 添加依赖
```XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>${revision}</version>
</dependency>
```
- 添加配置文件
![image-20200323161442058](/images/SpringBoot/image-20200323161442058.png)
![image-20200323161522570](/images/SpringBoot/image-20200323161522570.png)
- 此时配置文件地址出现了
```JAVA
protected String getSelfInitializationConfig() {
// 寻找配置文件
return findConfig(getStandardConfigLocations());
}
```
```JAVA
@Override
protected String[] getStandardConfigLocations() {
return new String[] { "logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml" };
}
```
```JAVA
private String findConfig(String[] locations) {
for (String location : locations) {
ClassPathResource resource = new ClassPathResource(location, this.classLoader);
if (resource.exists()) {
return "classpath:" + location;
}
}
return null;
}
```
- 此时自定义配置文件如何获取的已经明了
#### reinitialize
```JAVA
@Override
protected void reinitialize(LoggingInitializationContext initializationContext) {
// 日志上下文重新设置
getLoggerContext().reset();
getLoggerContext().getStatusManager().clear();
// 加载配置文件
loadConfiguration(initializationContext, getSelfInitializationConfig(), null);
}
```
```JAVA
@Override
protected void loadConfiguration(LoggingInitializationContext initializationContext, String location,
LogFile logFile) {
// 父类方法
super.loadConfiguration(initializationContext, location, logFile);
// 获取上下文
LoggerContext loggerContext = getLoggerContext();
// 停止并且重启
stopAndReset(loggerContext);
try {
// 配置文件加载
configureByResourceUrl(initializationContext, loggerContext, ResourceUtils.getURL(location));
}
catch (Exception ex) {
throw new IllegalStateException("Could not initialize Logback logging from " + location, ex);
}
List<Status> statuses = loggerContext.getStatusManager().getCopyOfStatusList();
StringBuilder errors = new StringBuilder();
for (Status status : statuses) {
if (status.getLevel() == Status.ERROR) {
errors.append((errors.length() > 0) ? String.format("%n") : "");
errors.append(status.toString());
}
}
if (errors.length() > 0) {
throw new IllegalStateException(String.format("Logback configuration error detected: %n%s", errors));
}
}
```
```JAVA
private void configureByResourceUrl(LoggingInitializationContext initializationContext, LoggerContext loggerContext,
URL url) throws JoranException {
if (url.toString().endsWith("xml")) {
// logback 日志操作
JoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);
// 设置上下文
configurator.setContext(loggerContext);
// 执行配置
configurator.doConfigure(url);
}
else {
new ContextInitializer(loggerContext).configureByResource(url);
}
}
```
- 执行配置属于logback 操作源码不在此进行分析

@ -0,0 +1,280 @@
# Spring Boot application 文件加载
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring-boot](https://github.com/SourceHot/spring-boot-read)
## 如何找到这个加载的过程
1. 创建配置文件`application.yml`
2. 全局搜索yml
![image-20200319083048849](/images/SpringBoot/image-20200319083048849.png)
3. 换成`properties`搜索
![image-20200319083140225](/images/SpringBoot/image-20200319083140225.png)
4. 我们以`yml`为例打上断点开始源码追踪
看到调用堆栈
![image-20200319083345067](/images/SpringBoot/image-20200319083345067.png)
- 一步一步回上去看如何调用具体方法的
## ConfigFileApplicationListener
- 配置文件监听器
### 调用过程
![image-20200319082131146](/images/SpringBoot/image-20200319082131146.png)
![image-20200319082544653](/images/SpringBoot/image-20200319082544653.png)
`org.springframework.boot.context.config.ConfigFileApplicationListener#addPropertySources`
```java
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
// 加载器加载信息
new Loader(environment, resourceLoader).load();
}
```
### Loader
- 配置资源加载器
构造方法
```java
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
// 环境配置
this.environment = environment;
// 占位符处理器
this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
// 资源加载器
this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
// 配置信息加载器初始化
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
getClass().getClassLoader());
}
```
- 熟悉的老朋友`this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader())` 看看**`spring.factories`**有什么
- 搜索目标: `org.springframework.boot.env.PropertySourceLoader`
![image-20200319084141748](/images/SpringBoot/image-20200319084141748.png)
![image-20200319084151997](/images/SpringBoot/image-20200319084151997.png)
观察发现里面有一个`YamlPropertySourceLoader`和我们之前找yml字符串的时候找到的类是一样的。说明搜索方式没有什么问题。
![image-20200319084357652](/images/SpringBoot/image-20200319084357652.png)
初始化完成,后续进行解析了
### load 方法
```java
void load() {
FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
(defaultProperties) -> {
this.profiles = new LinkedList<>();
this.processedProfiles = new LinkedList<>();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap<>();
// 初始化配置文件
initializeProfiles();
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
if (isDefaultProfile(profile)) {
addProfileToEnvironment(profile.getName());
}
load(profile, this::getPositiveProfileFilter,
addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
addLoadedPropertySources();
applyActiveProfiles(defaultProperties);
});
}
```
### initializeProfiles
- 初始化`private Deque<Profile> profiles;` 属性
- ![image-20200319084902957](/images/SpringBoot/image-20200319084902957.png)
### load
- `org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(org.springframework.boot.context.config.ConfigFileApplicationListener.Profile, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilterFactory, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)`
```JAVA
private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
getSearchLocations().forEach(
// 本地路径
(location) -> {
// 是不是文件夹
boolean isFolder = location.endsWith("/");
// 文件名,默认application
Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
// 循环加载
names.forEach((name) -> {
load(location, name, profile, filterFactory, consumer);
});
});
}
```
- 资源路径可能性
![image-20200319085446640](/images/SpringBoot/image-20200319085446640.png)
该方法采用循环每个路径下面都去尝试一遍
- 中间过程省略,我们直接看最后的加载行为
- `org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#loadDocuments`
```java
private List<Document> loadDocuments(PropertySourceLoader loader, String name, Resource resource)
throws IOException {
// 文档的缓存key
DocumentsCacheKey cacheKey = new DocumentsCacheKey(loader, resource);
// 文档信息
List<Document> documents = this.loadDocumentsCache.get(cacheKey);
if (documents == null) {
// 执行加载,将配置文件读取返回
List<PropertySource<?>> loaded = loader.load(name, resource);
// 数据转换
documents = asDocuments(loaded);
// 缓存设置
this.loadDocumentsCache.put(cacheKey, documents);
}
return documents;
}
```
此处的`loader.load()`调用具体的loader实现类进行执行方法
### yml 解析
```java
@Override
public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
if (!ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
throw new IllegalStateException(
"Attempted to load " + name + " but snakeyaml was not found on the classpath");
}
// 将资源转换成集合对象
List<Map<String, Object>> loaded = new OriginTrackedYamlLoader(resource).load();
if (loaded.isEmpty()) {
return Collections.emptyList();
}
List<PropertySource<?>> propertySources = new ArrayList<>(loaded.size());
for (int i = 0; i < loaded.size(); i++) {
String documentNumber = (loaded.size() != 1) ? " (document #" + i + ")" : "";
// 放入返回结果中
propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
Collections.unmodifiableMap(loaded.get(i)), true));
}
return propertySources;
}
```
![image-20200319090446231](/images/SpringBoot/image-20200319090446231.png)
- `PropertiesPropertySourceLoader`解析同理不在次展开描述了
### asDocuments
```JAVA
/**
* 将 {@link PropertySource} 转换成 {@link Document}
* @param loaded
* @return
*/
private List<Document> asDocuments(List<PropertySource<?>> loaded) {
if (loaded == null) {
return Collections.emptyList();
}
return loaded.stream().map(
// 循环创建新对象
(propertySource) -> {
// 对象创建
Binder binder = new Binder(ConfigurationPropertySources.from(propertySource),
this.placeholdersResolver);
/**
* 通过 {@link Binder} 将数据进行绑定,创建 {@link Document}进行返回
*/
return new Document(propertySource, binder.bind("spring.profiles", STRING_ARRAY).orElse(null),
getProfiles(binder, ACTIVE_PROFILES_PROPERTY),
getProfiles(binder, INCLUDE_PROFILES_PROPERTY));
}).collect(Collectors.toList());
}
```
-----

@ -0,0 +1,631 @@
# Spring Boot 自动装配
- Author: [HuiFer](https://github.com/huifer)
- 源码阅读仓库: [SourceHot-spring-boot](https://github.com/SourceHot/spring-boot-read)
- `org.springframework.boot.autoconfigure.SpringBootApplication`
```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}
```
## EnableAutoConfiguration
```java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
```
## AutoConfigurationImportSelector
- 类图
![image-20200320150642022](/images/SpringBoot/image-20200320150642022.png)
## getAutoConfigurationMetadata()
```JAVA
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(
// 加载配置元数据
getAutoConfigurationMetadata(), annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
private AutoConfigurationMetadata getAutoConfigurationMetadata() {
if (this.autoConfigurationMetadata == null) {
// 加载配置信息
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
}
return this.autoConfigurationMetadata;
}
```
- `org.springframework.boot.autoconfigure.AutoConfigurationMetadataLoader#loadMetadata(java.lang.ClassLoader)`
```JAVA
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
// 获取资源路径
Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while (urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
}
return loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
```
![image-20200320160423991](/images/SpringBoot/image-20200320160423991.png)
- `protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";`
注意: 这个文件在**target**编译后的文件夹中
相关 Issues : https://github.com/spring-projects/spring-boot/issues/11282
- 自动装配
`spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories`
该文件内存有:
```
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
```
![image-20200320162835665](/images/SpringBoot/image-20200320162835665.png)
同样找一下redis
![image-20200320163001728](/images/SpringBoot/image-20200320163001728.png)
- 仔细看`org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration`类
先说注解
```JAVA
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
```
### EnableConfigurationProperties
`自动映射一个POJO到Spring Boot配置文件默认是application.properties文件的属性集。`
- `org.springframework.boot.autoconfigure.data.redis.RedisProperties`
- 部分redis配置属性
```JAVA
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
/**
* Database index used by the connection factory.
*/
private int database = 0;
/**
* Connection URL. Overrides host, port, and password. User is ignored. Example:
* redis://user:password@example.com:6379
*/
private String url;
/**
* Redis server host.
*/
private String host = "localhost";
/**
* Login password of the redis server.
*/
private String password;
/**
* Redis server port.
*/
private int port = 6379;
/**
* Whether to enable SSL support.
*/
private boolean ssl;
/**
* Connection timeout.
*/
private Duration timeout;
/**
* Client name to be set on connections with CLIENT SETNAME.
*/
private String clientName;
}
```
- 找到一个我们用相同方式去寻找到别的一些属性处理如`org.springframework.boot.autoconfigure.jdbc.JdbcProperties` 具体展开请各位读者自行了解了
### AnnotationMetadata
回过头继续我们的主要流程
- `org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process`
![image-20200320163806852](/images/SpringBoot/image-20200320163806852.png)
再此之前我们看过了`getAutoConfigurationMetadata()`的相关操作
关注 `AnnotationMetadata annotationMetadata` 存储了一些什么
![image-20200320164145286](/images/SpringBoot/image-20200320164145286.png)
这里简单理解
1. mergedAnnotations 类相关的注解信息
2. annotationTypes 在启动类上的注解列表
### getAutoConfigurationEntry
```JAVA
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取注解属性值
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取候选配置信息
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 删除重复配置
configurations = removeDuplicates(configurations);
// 获取 exclude 属性
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 校验 exclude 类
checkExcludedClasses(configurations, exclusions);
// 配置中删除 exclude 的属性值
configurations.removeAll(exclusions);
// 过滤
configurations = filter(configurations, autoConfigurationMetadata);
// 触发自动配置事件
fireAutoConfigurationImportEvents(configurations, exclusions);
// 返回
return new AutoConfigurationEntry(configurations, exclusions);
}
```
### getAttributes
```java
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
// name = org.springframework.boot.autoconfigure.EnableAutoConfiguration , 这是一个固定的值
String name = getAnnotationClass().getName();
// 获取注解的属性
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}
```
![image-20200320171138431](/images/SpringBoot/image-20200320171138431.png)
### getCandidateConfigurations
- 读取`spring.factories`数据
```java
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 读取 org.springframework.boot.autoconfigure.EnableAutoConfiguration 相关配置
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
```
![image-20200320171734270](/images/SpringBoot/image-20200320171734270.png)
- 第一个是我自己写的一个测试用
```properties
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.sourcehot.service.HelloServiceAutoConfiguration
```
### removeDuplicates
- new 两个对象直接做数据转换,去重
```JAVA
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
```
### getExclusions
```JAVA
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
// 获取属性 exclude 值转换成list
excluded.addAll(asList(attributes, "exclude"));
// 获取属性 excludeName 值转换成list
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
// 获取 SpringBoot 本身的忽略配置属性
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
```
### getExcludeAutoConfigurationsProperty
```JAVA
private List<String> getExcludeAutoConfigurationsProperty() {
if (getEnvironment() instanceof ConfigurableEnvironment) {
Binder binder = Binder.get(getEnvironment());
// 取出 "spring.autoconfigure.exclude" 转换成list
return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
.orElse(Collections.emptyList());
}
String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
}
```
![image-20200323080611527](/images/SpringBoot/image-20200323080611527.png)
- 修改启动类
```JAVA
@SpringBootApplication(excludeName = { "org.sourcehot.service.HelloServiceAutoConfiguration" })
```
![image-20200323081009823](/images/SpringBoot/image-20200323081009823.png)
### checkExcludedClasses
```JAVA
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
List<String> invalidExcludes = new ArrayList<>(exclusions.size());
for (String exclusion : exclusions) {
//
if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
invalidExcludes.add(exclusion);
}
}
if (!invalidExcludes.isEmpty()) {
// 处理忽略的类
handleInvalidExcludes(invalidExcludes);
}
}
```
- `configurations.removeAll(exclusions)`
移除忽略的类
### filter
```JAVA
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
// 获取 AutoConfigurationImportFilter 相关配置
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
// 执行 aware 相关接口
invokeAwareMethods(filter);
// 比较
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return new ArrayList<>(result);
}
```
- `getAutoConfigurationImportFilters()` 从`spring.factories` 获取 `AutoConfigurationImportFilter`的接口
![image-20200323081903145](/images/SpringBoot/image-20200323081903145.png)
- 循环内执行`Aware`系列接口
`match`方法: `org.springframework.boot.autoconfigure.AutoConfigurationImportFilter#match`
- `filter.match(candidates, autoConfigurationMetadata)` 比较判断哪些是需要自动注入的类
![image-20200323082553595](/images/SpringBoot/image-20200323082553595.png)
### fireAutoConfigurationImportEvents
```JAVA
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
// 获取自动配置的监听器列表
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
// 创建 自动配置事件
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
// 执行 Aware 相关接口
invokeAwareMethods(listener);
// 监听器执行自动配置事件
listener.onAutoConfigurationImportEvent(event);
}
}
}
```
![image-20200323083149737](/images/SpringBoot/image-20200323083149737.png)
- `AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);`
![image-20200323083247061](/images/SpringBoot/image-20200323083247061.png)
- `org.springframework.boot.autoconfigure.AutoConfigurationImportListener#onAutoConfigurationImportEvent` 在执行自动配置时触发 , 实现类只有 **`ConditionEvaluationReportAutoConfigurationImportListener`**
```JAVA
@Override
public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
if (this.beanFactory != null) {
ConditionEvaluationReport report = ConditionEvaluationReport.get(this.beanFactory);
// 记录需要加载的配置
report.recordEvaluationCandidates(event.getCandidateConfigurations());
// 记录不需要加载的配置
report.recordExclusions(event.getExclusions());
}
}
```
![image-20200323083656670](/images/SpringBoot/image-20200323083656670.png)
- 初始化完
## process
- `org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process`
![image-20200323084922159](/images/SpringBoot/image-20200323084922159.png)
- 后续的一些行为相对简单,直接放个源码了.
```JAVA
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
// 自动装配信息
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(
// 加载配置元数据
getAutoConfigurationMetadata(), annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
// 循环需要自动注入的类
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
// 继续放入k,v
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
```
## selectImports
```java
@Override
public Iterable<Entry> selectImports() {
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
// 获取忽略的类
Set<String> allExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
// 获取需要注入的类
Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
// 把不需要自动注入的类从需要注入的类中移除
processedConfigurations.removeAll(allExclusions);
// 排序
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
```
后续由spring进行不再继续跟踪

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Loading…
Cancel
Save