zoukankan      html  css  js  c++  java
  • springboot源码解析

    复制代码
     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<Object> sources = new LinkedHashSet<Object>();
        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<ApplicationContextInitializer<?>> initializers;
     2 
     3     public void setInitializers(
     4             Collection<? extends ApplicationContextInitializer<?>> initializers) {
     5         this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
     6         this.initializers.addAll(initializers);
     7     }
     8 
     9     private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
    10         return getSpringFactoriesInstances(type, new Class<?>[] {});
    11     }
    12 
    13     private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
    14             Class<?>[] parameterTypes, Object... args) {
    15         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    16 
    17         // Use names and ensure unique to protect against duplicates
    18         Set<String> names = new LinkedHashSet<String>(
    19                 SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    20         List<T> instances = new ArrayList<T>(names.size());
    21 
    22         // Create instances from the names
    23         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      * <p>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 given
    10      * class loader.
    11      */
    12     public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    13         String factoryClassName = factoryClass.getName();
    14         try {
    15             Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
    16                     ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
    17             List<String> result = new ArrayList<String>();
    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 Initializers
    2 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<ApplicationListener<?>> 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<? extends ApplicationListener<?>> listeners) {
     9         this.listeners = new ArrayList<ApplicationListener<?>>();
    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 continue
    14         }
    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://zhaox.github.io/java/2016/03/22/spring-boot-start-flow 完成,该文的作者已经解析的很好了,我这里再抄一遍,只是为了加深记忆!!!

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

  • 相关阅读:
    RecyclerView 数据刷新的几种方式 局部刷新 notify MD
    【图片】批量获取几万张图片
    RV BaseRecyclerViewAdapterHelper 总结 MD
    RecyclerView.ItemDecoration 间隔线
    Kotlin【简介】Android开发 配置 扩展
    Kotlin 特性 语法糖 优势 扩展 高阶 MD
    一个十分简洁实用的MD风格的UI主框架
    折叠伸缩工具栏 CollapsingToolbarLayout
    FloatingActionButton FAB 悬浮按钮
    Glide Picasso Fresco UIL 图片框架 缓存 MD
  • 原文地址:https://www.cnblogs.com/softidea/p/6060004.html
Copyright © 2011-2022 走看看