摘要:本文重点分析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