盘古BPM体验地址    盘古BPM交流群盘古BPM交流群号:963222735

springboot ApplicationContextInitializer应用上下文初始化器源码分析-1

分享牛 4638℃

    摘要:本文重点分析springboot中的ApplicationContextInitializer应用上下文初始化器的相关源码。

在使用springboot的时候,我们只需要书写一个main方法,简单的配置一下即可开始进行快速开发中,启动springboot最简单的办法如下:

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
@EnableConfigurationProperties
@EnableScheduling//开启定时任务
@EnableTransactionManagement
public class Application extends SpringBootServletInitializer implements EmbeddedServletContainerCustomizer {
public static void main(String[] args) {
    BainuoSpringApplication springApplication = new BainuoSpringApplication(Application.class);
    springApplication.addListeners(new BainuoApplicationEnvironmentPreparedEventListener());
    springApplication.run(args);
}

本文我们重点关注一下ApplicationContextInitializer的初始化逻辑,首先我们看一下springApplication类的构造函数,相关代码如下所示:

public SpringApplication(Object... sources) {
        initialize(sources);
}

initialize方法如下:

private void initialize(Object[] sources) {
    if (sources != null && sources.length > 0) {
        this.sources.addAll(Arrays.asList(sources));
}
//判断是否是web环境,只要springboot启动的环境中包含javax.servlet.Servlet, org.springframework.web.context.ConfigurableWebApplicationContext  任意一个即认为是web环境
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//设置一系列的监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

我们重点看一下setInitializers方法:

private List<ApplicationContextInitializer<?>> initializers;
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}

所有的初始化器最终会被设置到initializers集合中。

因此,我们退回一步,继续看一下setInitializers((Collection) getSpringFactoriesInstances(

ApplicationContextInitializer.class));所做的事情,

getSpringFactoriesInstances方法如下:

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
       return getSpringFactoriesInstances(type, new Class<?>[] {});
}

注意:type类型是org.springframework.context.ApplicationContextInitializer。

继续跟进getSpringFactoriesInstances(type, new Class<?>[] {})方法,如下所示:

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
    //获取类加载器
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // 获取所有的jar包中META-INF/spring.factories中配置的ApplicationContextInitializer	属性
    Set<String> names = new LinkedHashSet<String>(
    SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //实例化上一步中配置的类
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
    classLoader, args, names);
    //将所有的初始化器进行排序
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

SpringFactoriesLoader.loadFactoryNames方法

SpringFactoriesLoader.loadFactoryNames方法代码如下:

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
//factoryClassName =org.springframework.context.ApplicationContextInitializer
String factoryClassName = factoryClass.getName();
try {
//获取jar中的META-INF/spring.factories文件
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
//循环遍历资源文件
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
//加载所有的META-INF/spring.factories文件
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
//获取属性org.springframework.context.ApplicationContextInitializer
	String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
}
}


上面函数的处理逻辑,可以分为如下几个步骤:

1、定义要获取的属性,key为org.springframework.context.ApplicationContextInitializer。

2、遍历查找jar包以及项目中的META-INF/spring.factories文件。

3、读取META-INF/spring.factories文件。

4、查找key为org.springframework.context.ApplicationContextInitializer的值。

5、将查找到的值添加到集合中。

在springboot中初始化器有如下几个:

spring-boot-devtools-1.5.8.RELEASE.jar

# Application Initializers

org.springframework.context.ApplicationContextInitializer=\

org.springframework.boot.devtools.restart.RestartScopeInitializer

spring-boot-1.5.8.RELEASE.jar

# 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.context.embedded.ServerPortInfoApplicationContextInitializer

spring-boot-autoconfigure-1.5.8.RELEASE.jar

# Initializers

org.springframework.context.ApplicationContextInitializer=\

org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\

org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

通过上述的配置文件我们可以看出一共是7个初始化器。

createSpringFactoriesInstances方法:

private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
//实例化集合
List<T> instances = new ArrayList<T>(names.size());
for (String name : names) {
try {
//反射实例化类
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
}
}
return instances;
}

本文暂时先讲解到这里,后续我们再来看各个初始化器都是做什么的。

转载请注明:分享牛 » springboot ApplicationContextInitializer应用上下文初始化器源码分析-1