0
点赞
收藏
分享

微信扫一扫

SpringBoot源码分析 (构造方法) (二)

SpringBoot源码分析 (构造方法) (二)_bootstrap
SpringBoot源码分析 (构造方法) (二)_spring_02

构造方法解析

SpringBoot源码分析 (构造方法) (二)_加载_03
SpringBoot源码分析 (构造方法) (二)_加载_04

  1. 获取BeanDefinition 主源
  2. 推断应用类型
  3. ApplicationContext初始化器
  4. 监听器和事件
  5. 主类推断

文章目录

  • ​​构造方法解析​​
  • ​​1.1 获取BeanDefinition 主源​​
  • ​​1.2 推断应用类型​​
  • ​​1.3 ApplicationContext初始化器​​
  • ​​1.4 监听器和事件​​
  • ​​1.5 主类推断​​


1.1 获取BeanDefinition 主源

SpringBoot源码分析 (构造方法) (二)_加载_05
这里可以理解为获取一个ResourceLoader 用于获取BeanDefinition
然后断言主源是否存在
然后将主源添加到集合中, 这个集合为primarySources
集合用于后续解析获取到BeanDefinition

1.2 推断应用类型

SpringBoot源码分析 (构造方法) (二)_bootstrap_06
用于判断是SERVLET 还是 REACTIVE 还是 NONE

static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}

1.3 ApplicationContext初始化器

初始化进行增强

SpringBoot源码分析 (构造方法) (二)_springboot_07

private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
getSpringFactoriesInstances(Bootstrapper.class).stream()
.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
.forEach(initializers::add);
initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
return initializers;
}

springApplication.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// context
GenericApplicationContext context = (GenericApplicationContext) applicationContext;
context.registerBean("bean1", Bean1.class);
}
});

在spring.factories下面的ApplicationContextInitializer加载类

spring-boot项目下

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

spring-boot-autoconfigure项目下

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

SpringBoot源码分析 (构造方法) (二)_加载_08
 具体的加载方法为 getSpringFacotiesInstance()方法

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

SpringFactoriesLoader.loadFactoryNames(type, classLoader)中具体查看加载文件的过程
SpringBoot源码分析 (构造方法) (二)_spring_09
loadSpringFactories()

SpringBoot源码分析 (构造方法) (二)_springboot_10
通过 loadSpringFactories 方法我们看到把 spring.factories文件中的所有信息都加载到了内存中了,但是我们现在只需要加载 ApplicationContextInitializer类型的数据。

getOrDefault():

default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}

SpringBoot源码分析 (构造方法) (二)_加载_11
 然后会根据反射获取对应的实例对象。
SpringBoot源码分析 (构造方法) (二)_加载_12
SpringBoot源码分析 (构造方法) (二)_加载_13
​​​getSpringFactoriesInstances​​​方法就是帮我们定义在​​META-INF/spring.factories​​​文件中的认为是​​ApplicationContextInitializer​​​的值, 并通过反射获取实例对象, 然后将实例对象存储在​​initializers​​属性中。

SpringBoot源码分析 (构造方法) (二)_加载_14

1.4 监听器和事件

注册监听器, 用于后面使用
SpringBoot源码分析 (构造方法) (二)_spring_15
要获取的 META-INF/spring.factories文件中定义ApplicationListener的值
SpringBoot源码分析 (构造方法) (二)_加载_16

SpringBoot源码分析 (构造方法) (二)_springboot_17

加入到​​listeners​​ 属性中。

1.5 主类推断

判断main方法是哪个类
SpringBoot源码分析 (构造方法) (二)_加载_18
这里我利用反射调用这个方法

@SpringBootApplication
public class Main {
public static void main(String[] args)throws Exception{
SpringApplication app = new SpringApplication(Main.class);
app.run(args);
Method method = SpringApplication.class.getDeclaredMethod("deduceMainApplicationClass");
method.setAccessible(true);
System.out.println(method.invoke(app));

}
}

获取类名
SpringBoot源码分析 (构造方法) (二)_springboot_19
SpringBoot源码分析 (构造方法) (二)_bootstrap_20

举报

相关推荐

0 条评论