• springboot启动过程


    使用了很长时间的springboot了,一直都知道它简单易用,简化了框架的搭建过程,但是还是不知道它是如何启动的,今天就跟着springboot的源码,去探探这其中的奥妙

        以下是spring应用的启动:
    
    @SpringBootApplication
    public class Application extends WebMvcConfigurerAdapter {
    	public static void main(String[] args) {
    		//加载配置文件
    		System.setProperty("spring.config.location","classpath:db_config.properties,classpath:mq.properties");
    		SpringApplication.run(Application.class, args);
    
    	}
    }
    

    然后我们跟着Run方法进去

    public ConfigurableApplicationContext run(String... args) {
        //一开始就是一个StopWatch 类,这个类的主要作用是记录容器启动用时
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        FailureAnalyzers analyzers = null;
        this.configureHeadlessProperty();
        //加载SPI文件
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();
    
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            new FailureAnalyzers(context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            listeners.finished(context, (Throwable)null);
            stopWatch.stop();
            if(this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
    
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
            throw new IllegalStateException(var9);
        }
    }
    

    第一步:可以看到,一开始是一个StopWatch类,该类的作用比较单一,就是记录springboot的启动用时,我们启动springboot完成后会在控制台springboot启动所花的时间,就是由它来完成的

    //然后我们看看this.createApplicationContext()方法:
    private void configureHeadlessProperty() {
        System.setProperty("java.awt.headless", System.getProperty("java.awt.headless", Boolean.toString(this.headless)));
    }
    //主要是用来设置系统属性,具体这个属性有何作用,有待探究
    

    第二步:创建SpringApplicationRunListeners

    //接下来我们看看springboot是如何去初始化监听器SpringApplicationRunListeners的。this.getRunListeners(args)方法如下:
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, new Object[]{this, args}));
    }
    //利用传入的参数args去创建一个SpringApplicationRunListeners实例,此处会去获取一个SpringFactory的实例,下面我们重点看看是如何来获取该SpringFactory实例的
    private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }
    //首先获取当前线程的类加载器,然后通过SpringFactoriesLoader去加载SpringApplicationRunListener这个类,接下来看看在加载SpringApplicationRunListener这个spring应用的运行监听器时做了什么事情
    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
    
        try {
            Enumeration ex = classLoader != null?classLoader.getResources("META-INF/spring.factories"):ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();
    
            while(ex.hasMoreElements()) {
                URL url = (URL)ex.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }
    
            return result;
        } catch (IOException var8) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
        }
    }
    //首先通过当前线程的类加载器获取Springboot项目META-INF下面的spring.factories文件,找到该文件,我们可以看到该文件中配置了PropertySource Loaders(属性来源加载)、运行监听器EventPublishingRunListener、运用上下文初始化工具、应用监听器等等一系列的自动化配置,都是从这里加载到应用中来的。加载完成之后,SpringFactory通过反射来获取这些类的实例,然后放入到SpringApplicationRunListeners中,至此,SpringApplicationRunListeners初始化完成。这里,我们看看SpringApplicationRunListeners中有些什么,源码如下:
    class SpringApplicationRunListeners {
    	private final Log log;
    	private final List<SpringApplicationRunListener> listeners;
    
    	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
    		this.log = log;
    		this.listeners = new ArrayList(listeners);
    	}
    }
    //有一个log,用于记录日志,然后就是一个final的list,里面就是之前初始化时从配置中获取的各种listener
    
    再次回顾一下SpringApplicationRunListeners的创建过程:首先获取当前线程的ClassLoader,然后通过SpringFactoriesLoader去加载Springboot项目中META-INF文件夹下的spring.factories配置文件,之后通过反射获取相关listener实例,存储到SpringApplicationRunListeners的list属性中,由此完成SpringApplicationRunListeners的初始化过程

    第三步:启动SpringApplicationRunListeners中所有的监听器

    第四步:环境准备

    第五步:打印Banner

    第六步:创建上下文

  • 相关阅读:
    学习MyBatis时报的错
    Day01
    PAT乙级01
    基于python-django框架的支付宝支付案例
    单线程与多线程的应用 --Python3
    Python异常 --Python
    有四个数字能组成多少个互不相同的三位数 --Python
    with as用法 --Python
    采用霍夫曼编码(Huffman)画出字符串各字符编码的过程并求出各字符编码 --多媒体技术与应用
    函数和代码复用 --Python
  • 原文地址:https://www.cnblogs.com/canmeng-cn/p/8627660.html
Copyright © 2020-2023  润新知