探索SpringBoot启动源码

一. 启动原理分析

@SpringBootApplication

public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);

    }

}  

这是一个标准的springboot启动项目的,首先从@SpringBootApplication这个注解开始解读,阅读过源码发现这其实就是一个集合了多个spring注解的自定义注解(这也是springboot的产生原因,为了更敏捷地开发spring应用),源码如下:

@Target(ElementType.TYPE)  //注解适用范围,其中TYPE用于描述类、接口(包括主借类型)或enum声明

@Retention(RetentionPolicy.RUNTIME)//注解的生命周期,保留到class文件中(也就是说该注解在什么时期可见)

@Documented //表明这个注解应该被javadoc记录

@Inherited //子类可以继承该注解

@SpringBootConfiguration  //进入该注解可以发现继承了configuration,表示当前是注解类

@EnableAutoConfiguration //开启了sringboot的注解功能,springboot的四大神奇之一,其借助@import的帮助

@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))  //扫描路劲设置(具体待确认)

public @interface SpringBootApplication {

......

}

      通过源码阅读可以发现上述注解中最主要其实就是@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan,三个注解作用可自行查看详细介绍。

下面从这个run方法开始跟踪,

 SpringApplication.run(Application.class, args);

//source就是对应启动类的class
public static ConfigurableApplicationContext run(Object source, String... args) {
        return run(new Object[] { source }, args);
    } 

//SpringApplication初始化解读如下:
//第一步:调用构造函数

public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        return new SpringApplication(sources).run(args);

//通过构造函数生成一个新的SpringApplication,再调用它的run方法
    }

//第二步:构造函数调用初始化方法initialize,参数就是启动类的class
public SpringApplication(Object... sources) {
        initialize(sources);
    }

/*-----------------------------------------------//初始化方法解读----------------------------------------------------------------------------------*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
        if (sources != null && sources.length > 0) {
            this.sources.addAll(Arrays.asList(sources));
        }

        /*判断是否为web应用,通过deduceMainApplicationClass方法判断是否加载的有{ 
   "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" }*/
        this.webEnvironment = deduceWebEnvironment();
     从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;
     然后保存起来*/

        setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));
      /* 从spring.factories文件中找出key为ApplicationListener的类并实例化后设置到SpringApplication的listeners属性中。这个过程就是找出所有的应用程序事件监听器*/
        setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
//获取到main方法所在的类
    }

/*--------------------------------------------------------------------------------------------------------------------------------------------------------------*/

//获取所有实例
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
            Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        // 通过classLoader 从类路径下找到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;
    }

/*-----------------------------------------------------------------------------------------------------------------------------------------------------*/

// loadFactoryNames获取所有的的ApplicationContextInitializer
/*通过给定的类加载器classLoader 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer*/

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        try {

 /*获取所有jar下面的META-INF/spring.factories 文件路径例如: jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot/1.5.10.RELEASE/spring-boot-1.5.10.RELEASE.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();

                //从给定资源加载属性(配置文件例如:.../spring.factories)
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                //读取配置文件中的ApplicationContextInitializer
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }
            return result;
        }
        catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                    "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
        }
    }
 

/*---------------------------------------------------initialize()初始化方法结束,开始执行run-----------------------------------------------*/ 

public ConfigurableApplicationContext run(String... args) {
//开启监听(stopWatch)用来记录任务的启动 结束时间,是一个非线程的安全的,如果自己使用要考虑多线程的情况.
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
//声明IOC容器
   ConfigurableApplicationContext context = null;
//设置headless 略
   configureHeadlessProperty();
//用SpringApplicationRunListeners来加载ApplicationListener中的业务.
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.started();
   try {
//封装命令行参数
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
//准备环境
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
//控制台打印Spring banner图标
      Banner printedBanner = printBanner(environment);
//创建ApplicationContext;决定创建web的ioc还是普通的ioc
      context = createApplicationContext();

 /*准备上下文环境:将environment保存到ioc中;applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法回调所有的SpringApplicationRunListener的contextPrepared();prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();*/
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
/*刷新容器:ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版。扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)*/
      refreshContext(context);//IOC创建完毕
/*从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调 
ApplicationRunner先回调,CommandLineRunner再回调*/
      afterRefresh(context, applicationArguments);
//所有的SpringApplicationRunListener回调finished方法
      listeners.finished(context, null);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
      return context;
   }
   catch (Throwable ex) {
      handleRunFailure(context, listeners, ex);
      throw new IllegalStateException(ex);
   }
}

 /*----------------------------------------------获取环境prepareEnvironment()方法解读------------------------------------------------------------*/

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   // 获取或者生成环境
   ConfigurableEnvironment environment = getOrCreateEnvironment();
//  配置环境
        configureEnvironment(environment, applicationArguments.getSourceArgs());
    //创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成
   listeners.environmentPrepared(environment);
   if (isWebEnvironment(environment) && !this.webEnvironment) {
      environment = convertToStandardEnvironment(environment);
   }
   return environment;
}

/*-------------------------------------------------------准备上下文环境 prepareContext()-----------------------------------------------------------*/ 

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {

         //给IOC容器赋值environment
        context.setEnvironment(environment);

        //IOC后置处理,注册了组件
        postProcessApplicationContext(context);

         //回调之前保存的所有的ApplicationContextInitializer的initialize方法
        applyInitializers(context);  

        //执行所有Listeners的contextPrepared()方法
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
 //日志记录
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }


        // 把命令行参数的类applicationArguments 注册到IOC容器
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {

            //注册打印的banner
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // 获取主类信息
        Set<Object> sources = getSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[sources.size()]));

    //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
        listeners.contextLoaded(context);
}

/*----------------getInitializers() :获取到之前获取的ApplicationContextInitializer 实例,执行initialize()方法---------------------*/ 

protected void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
                    initializer.getClass(), ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
}

/*--------------------------------------------------刷新容器refreshContext(context);-----------------------------------------------------*/ 

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {

            // 准备此上下文以进行刷新。
            prepareRefresh();
            // 告诉子类刷新内部bean工厂。
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            //准备使用这个beanFatory
             //配置工厂的标准上下文特性,
              //*如上下文的类加载器和后置处理器。
 
          prepareBeanFactory(beanFactory);
            try {
                // 允许在上下文子类中对bean工厂进行后处理。
                postProcessBeanFactory(beanFactory);

                // 调用工厂处理器在上下文中注册为bean。
                invokeBeanFactoryPostProcessors(beanFactory);

                //注册拦截Bean创建的Bean处理,这里只是注册,真正调用是再拿去Bean的时候                                                                   registerBeanPostProcessors(beanFactory);


                // 初始化此上下文的消息源,即不同语言的消息体,国际化处理
                initMessageSource();

               //初始化应用消息广播器,并放到applicationEventMulticaster bean中
                initApplicationEventMulticaster();

                //在特殊的context子类中初始化其他的特殊bean.
                onRefresh();

                // 在所有注册的bean中查找Listener bean,注册到消息广播中
                registerListeners();

              //创建所有非懒加载的单例类(并invoke BeanPostProcessors)               

                finishBeanFactoryInitialization(beanFactory);
               

              //完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
                finishRefresh();
            }
            catch (BeansException ex) {
.......               

          }
}

/*-----------------------------------------------------afterRefresh(context, applicationArguments);------------------------------------------*/ 

protected void afterRefresh(ConfigurableApplicationContext context,
            ApplicationArguments args) {
        callRunners(context, args);
}

//获取ApplicationRunner 和 CommandLineRunner   并会调
private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<Object>();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        for (Object runner : new LinkedHashSet<Object>(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
}

调用SpringApplication.run()方法(时序图步骤3) 
构造SpringApplicationRunListeners 实例(时序图步骤3.1.1)
发布ApplicationStartedEvent事件(时序图步骤3.1.2)
SpringApplicationRunListeners 实例准备环境信息(时序图步骤3.1.3)
创建ApplicationContext对象(时序图步骤3.1.4)
ApplicationContext实例准备环境信息(时序图步骤3.1.5)
刷新的上下文(时序图步骤3.1.6)

参考: https://www.jianshu.com/p/caa9cd010940

            https://www.jianshu.com/p/464d04c36fb1

            https://www.jianshu.com/p/64aac6461d5b

            https://www.cnblogs.com/wudi-dudu/p/7871405.html

            https://www.cnblogs.com/kaituorensheng/p/7105639.html

            https://www.cnblogs.com/dooor/p/5346333.html

            https://blog.csdn.net/zhang_ly520/article/details/83320581

猜你喜欢

转载自blog.csdn.net/weixin_40151613/article/details/87887014