博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springboot源码解析 - 构建SpringApplication
阅读量:5754 次
发布时间:2019-06-18

本文共 8919 字,大约阅读时间需要 29 分钟。

复制代码
1 package com.microservice.framework; 2  3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5  6 @SpringBootApplication 7 public class MySpringAplication { 8  9     public void run(String[] args) {10         SpringApplication sa = new SpringApplication(MySpringAplication.class);11         sa.run(args);12     }13 14 }
复制代码

SpringBoot启动过程:

1、构建SpringApplication对象

2、执行run()

一、构建SpringApplication对象

1     /**2      * The application context will load beans from the specified sources 3      */4     public SpringApplication(Object... sources) {5         initialize(sources);6     }

说明:

  • 实例化该类的时候会加载bean到applicationContext中去
  • 这里的入参是MySpringApplication.class这样一个Class<com.microservice.framework.MySpringApplication>对象
复制代码
private final Set sources = new LinkedHashSet();    private boolean webEnvironment;    private Class
mainApplicationClass; private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
复制代码

步骤:

  • 将传入的MySpringApplication.class对象放入Set集合
  • 判断是否是web环境
  • 创建ApplicationInitializer列表
  • 初始化ApplicationListener列表
  • 初始化主类mainApplicationClass

1.1、将传入的MySpringApplication.class对象放入Set集合

1.2、判断是否是web环境:

复制代码
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",            "org.springframework.web.context.ConfigurableWebApplicationContext" };    private boolean deduceWebEnvironment() {        for (String className : WEB_ENVIRONMENT_CLASSES) {            if (!ClassUtils.isPresent(className, null)) {                return false;            }        }        return true;    }
复制代码

说明:通过在classpath中查看是否存在WEB_ENVIRONMENT_CLASSES这个数组中所包含的所有类(实际上就是2个类),如果存在那么当前程序即是一个Web应用程序,反之则不然。

1.3、创建ApplicationContextInitializer列表

复制代码
1     private List
> initializers; 2 3 public void setInitializers( 4 Collection
> initializers) { 5 this.initializers = new ArrayList
>(); 6 this.initializers.addAll(initializers); 7 } 8 9 private
Collection
getSpringFactoriesInstances(Class
type) {10 return getSpringFactoriesInstances(type, new Class
[] {});11 }12 13 private
Collection
getSpringFactoriesInstances(Class
type,14 Class
[] parameterTypes, Object... args) {15 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();16 17 // Use names and ensure unique to protect against duplicates18 Set
names = new LinkedHashSet
(19 SpringFactoriesLoader.loadFactoryNames(type, classLoader));20 List
instances = new ArrayList
(names.size());21 22 // Create instances from the names23 for (String name : names) {24 try {25 Class
instanceClass = ClassUtils.forName(name, classLoader);26 Assert.isAssignable(type, instanceClass);27 Constructor
constructor = instanceClass.getConstructor(parameterTypes);28 T instance = (T) constructor.newInstance(args);29 instances.add(instance);30 }31 catch (Throwable ex) {32 throw new IllegalArgumentException(33 "Cannot instantiate " + type + " : " + name, ex);34 }35 }36 37 AnnotationAwareOrderComparator.sort(instances);38 return instances;39 }
复制代码

步骤:

  • 调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)来获取所有Spring Factories的名字,(这里是获取了四个ApplicationContextInitializer实现类的全类名,见下边)
  • 为每一个Spring Factories根据读取到的名字创建其对象。(这里创建了4个对象)
  • 将创建好的对象列表排序并返回。

其中,SpringFactoriesLoader.loadFactoryNames(type, classLoader)如下:

复制代码
1     /** 2      * The location to look for factories. 3      * 

Can be present in multiple JAR files. 4 */ 5 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; 6 7 /** 8 * Load the fully qualified class names of factory implementations of the 9 * given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given10 * class loader.11 */12 public static List

loadFactoryNames(Class
factoryClass, ClassLoader classLoader) {13 String factoryClassName = factoryClass.getName();14 try {15 Enumeration
urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :16 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));17 List
result = new ArrayList
();18 while (urls.hasMoreElements()) {19 URL url = urls.nextElement();20 Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));21 String factoryClassNames = properties.getProperty(factoryClassName);22 result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));23 }24 return result;25 }26 catch (IOException ex) {27 throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +28 "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);29 }30 }

复制代码

META-INF/spring-factories

1 # Application Context Initializers2 org.springframework.context.ApplicationContextInitializer=\3 org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\4 org.springframework.boot.context.ContextIdApplicationContextInitializer,\5 org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\6 org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer

说明:

  • 从所有jar获取所有的META-INF/spring-factories文件。(这里只有spring-boot-1.3.0.RELEASE.jar下有一个)
  • 遍历每一个spring-factories文件,并获取其下key为factoryClass.getName()(这里是入参

    org.springframework.context.ApplicationContextInitializer)的value(这里有以上四个ApplicationContextInitializer实现类)

以上四个类的作用:

 

至此,设置ApplicationContextInitialize就完成了。

总结:整个setInitializers实际上就是初始化了SpringApplication的属性List<ApplicationContextInitializer<?>> initializers为一个ArrayList列表,该列表中有四个实例:

  • ConfigurationWarningsApplicationContextInitializer的实例
  • ContextIdApplicationContextInitializer的实例
  • DelegatingApplicationContextInitializer实例
  • ServerPortInfoApplicationContextInitializer实例

1.4、初始化ApplicationListener列表

复制代码
1     private List
> listeners; 2 3 /** 4 * Sets the {@link ApplicationListener}s that will be applied to the SpringApplication 5 * and registered with the {@link ApplicationContext}. 6 * @param listeners the listeners to set 7 */ 8 public void setListeners(Collection
> listeners) { 9 this.listeners = new ArrayList
>();10 this.listeners.addAll(listeners);11 }
复制代码

META-INF/spring-factories

复制代码
1 # Application Listeners 2 org.springframework.context.ApplicationListener=\ 3 org.springframework.boot.builder.ParentContextCloserApplicationListener,\ 4 org.springframework.boot.context.FileEncodingApplicationListener,\ 5 org.springframework.boot.context.config.AnsiOutputApplicationListener,\ 6 org.springframework.boot.context.config.ConfigFileApplicationListener,\ 7 org.springframework.boot.context.config.DelegatingApplicationListener,\ 8 org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\ 9 org.springframework.boot.logging.ClasspathLoggingApplicationListener,\10 org.springframework.boot.logging.LoggingApplicationListener
复制代码

以上八个listener的作用如下:

至此,整个setListeners方法结束,初始化了一个包含以上8个ApplicationListener实例的List集合。

 

1.5、初始化主类mainApplicationClass

复制代码
1     private Class
mainApplicationClass; 2 3 private Class
deduceMainApplicationClass() { 4 try { 5 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); 6 for (StackTraceElement stackTraceElement : stackTrace) { 7 if ("main".equals(stackTraceElement.getMethodName())) { 8 return Class.forName(stackTraceElement.getClassName()); 9 }10 }11 }12 catch (ClassNotFoundException ex) {13 // Swallow and continue14 }15 return null;16 }
复制代码

说明:获取main()方法所在的主类Class对象,并赋值给SpringApplication的mainApplicationClass属性。

至此,SpringApplication对象初始化完成了。

总结:整个SpringApplication初始化的过程,就是初始化了

  • 一个包含入参MySpringApplication.class的sources的Set<Object>
  • 一个当前环境是否是web环境的boolean webEnvironment
  • 一个包含4个ApplicationContextInitializer实例的List
  • 一个包含8个ApplicationListener实例的List
  • 一个main方法所在的主类的Class对象。

注意:

本文基本参照完成,该文的作者已经解析的很好了,我这里再抄一遍,只是为了加深记忆!!!

 

http://www.cnblogs.com/java-zhao/p/5540309.html

 

转载于:https://www.cnblogs.com/softidea/p/6060004.html

你可能感兴趣的文章
java泛型中特殊符号的含义
查看>>
一秒 解决 ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'mysql 问题
查看>>
Android组件化最佳实践 ARetrofit原理
查看>>
舍弃浮躁, 50条重要的C++学习建议
查看>>
同步手绘板——将View的内容映射成Bitmap转图片导出
查看>>
【Android游戏开发之十】(优化处理)详细剖析Android Traceview 效率检视工具!分析程序运行速度!并讲解两种创建SDcard方式!...
查看>>
微信小程序之wx.navigateback往回携带参数
查看>>
陌陌和请吃饭之类的应用,你要是能玩转,那就厉害了
查看>>
递归的运行机制简单理解
查看>>
汉字转阿斯克马值
查看>>
Java 栈与堆简介
查看>>
【supervisord】部署单进程服务的利器
查看>>
zabbix oracle监控插件orabbix部署安装
查看>>
python3 通过qq 服务器 发送邮件
查看>>
java 多线程踩过的坑
查看>>
部署Replica Sets及查看相关配置
查看>>
倒序显示数组(从右往左)
查看>>
LeetCode2_Evaluate Reverse Polish Notation评估逆波兰表达式(栈)
查看>>
文献综述二:UML技术在行业资源平台系统建模中的应用
查看>>
阿里云服务器 linux下载 jdk
查看>>