1. 程式人生 > >spring boot 2.0 源碼分析(五)

spring boot 2.0 源碼分析(五)

pen div shutdown down etc messages servle started fec

在上一篇文章中我們詳細分析了spring boot是如何準備上下文環境的,今天我們來看一下run函數剩余的內容。還是先把run函數貼出來:

    /**
     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * @param args the application arguments (usually passed from a Java main method)
     * @return a running {@link ApplicationContext}
*/ public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty
(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment
(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }

我們接著往下看,來看一下this.refreshContext(context);函數,這個函數用於刷新上下文,跟蹤到源碼看一下:

    private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }

在refreshContext函數中,第一行調用了refresh(context);跳轉了一下,下面的代碼是註冊了一個應用關閉的函數鉤子。
先來看refresh(context);函數:

    /**
     * Refresh the underlying {@link ApplicationContext}.
     * @param applicationContext the application context to refresh
     */
    protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext) applicationContext).refresh();
    }

通過代碼跟蹤分析發現,其實是調用了AbstractApplicationContext中的refresh方法。
在ServletWebServerApplicationContext和ReactiveWebServerApplicationContext的refresh函數中都是調用了super.refresh();

    public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if(this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization \
                    - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

在這段代碼中我們可以看到,其是使用了上下文中的startupShutdownMonitor屬性創建一個同步代碼庫來執行的刷新動作。首先是實驗this.prepareRefresh();準備刷新上下文:

    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
        if(this.logger.isInfoEnabled()) {
            this.logger.info("Refreshing " + this);
        }

        this.initPropertySources();
        this.getEnvironment().validateRequiredProperties();
        this.earlyApplicationEvents = new LinkedHashSet();
    }

接著獲取了bean工廠以後,設置了一些bean工廠的環境:

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.setBeanClassLoader(this.getClassLoader());
        beanFactory.setBeanExpressionResolver(
        new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(
        new ResourceEditorRegistrar(this, this.getEnvironment()));
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
        if(beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(
            new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        if(!beanFactory.containsLocalBean("environment")) {
            beanFactory.registerSingleton("environment", this.getEnvironment());
        }

        if(!beanFactory.containsLocalBean("systemProperties")) {
            beanFactory.registerSingleton("systemProperties", 
            this.getEnvironment().getSystemProperties());
        }

        if(!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", 
            this.getEnvironment().getSystemEnvironment());
        }

    }

接下來是發送了一個bean工廠的處理信號,其中ServletWebServerApplicationContext中的實現是在bean工廠裏添加了一個WebApplicationContextServletContextAwareProcessor處理器:

    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.addBeanPostProcessor(
        new WebApplicationContextServletContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    }

緊接著就是調用了這處理器,並且註冊到bean工廠。然後就是分別調用了initMessageSource()和initApplicationEventMulticaster()用於初始化監聽器和監聽管理器:

    protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if(beanFactory.containsLocalBean("messageSource")) {
            this.messageSource = (MessageSource)beanFactory
            .getBean("messageSource", MessageSource.class);
            if(this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource dms = (HierarchicalMessageSource)this.messageSource;
                if(dms.getParentMessageSource() == null) {
                    dms.setParentMessageSource(this.getInternalParentMessageSource());
                }
            }

            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Using MessageSource [" + this.messageSource + "]");
            }
        } else {
            DelegatingMessageSource dms1 = new DelegatingMessageSource();
            dms1.setParentMessageSource(this.getInternalParentMessageSource());
            this.messageSource = dms1;
            beanFactory.registerSingleton("messageSource", this.messageSource);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Unable to locate MessageSource with name 
                \'messageSource\': using default [" + this.messageSource + "]");
            }
        }

    }

    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if(beanFactory.containsLocalBean("applicationEventMulticaster")) {
            this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory
            .getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Using ApplicationEventMulticaster [" + 
                this.applicationEventMulticaster + "]");
            }
        } else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton("applicationEventMulticaster", 
            this.applicationEventMulticaster);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Unable to locate ApplicationEventMulticaster with name 
                \'applicationEventMulticaster\':
                 using default [" + this.applicationEventMulticaster + "]");
            }
        }

    }

在initMessageSource函數中會首先判斷beanFactory工廠中是否已經存在messageSource,如果不存在就會為當前的messageSource創建一個新的DelegatingMessageSource。
initApplicationEventMulticaster的初始化方式跟initMessageSource差不多,這裏不再多述。
繼續看run函數,接下來調用onRefresh()函數,這個函數只是發送一個刷新的事件,源碼中並沒有具體的實現。
接著放下看,this.registerListeners();把spring容器內的listener和beanfactory的listener都添加到廣播器中:

    protected void registerListeners() {
        Iterator listenerBeanNames = this.getApplicationListeners().iterator();

        while(listenerBeanNames.hasNext()) {
            ApplicationListener earlyEventsToProcess = (ApplicationListener)listenerBeanNames.next();
            this.getApplicationEventMulticaster().addApplicationListener(earlyEventsToProcess);
        }

        String[] var6 = this.getBeanNamesForType(ApplicationListener.class, true, false);
        String[] var7 = var6;
        int var3 = var6.length;

        for(int earlyEvent = 0; earlyEvent < var3; ++earlyEvent) {
            String listenerBeanName = var7[earlyEvent];
            this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        Set var8 = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if(var8 != null) {
            Iterator var9 = var8.iterator();

            while(var9.hasNext()) {
                ApplicationEvent var10 = (ApplicationEvent)var9.next();
                this.getApplicationEventMulticaster().multicastEvent(var10);
            }
        }

    }

通過this.finishBeanFactoryInitialization(beanFactory);實例化BeanFactory 中已經被註冊但是沒被實例化的所有實例。初始化的過程中各種BeanPostProcessor就開始生效了:

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        if(beanFactory.containsBean("conversionService") && 
        beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
        
            beanFactory.setConversionService((ConversionService)beanFactory
            .getBean("conversionService", ConversionService.class));
        }

        if(!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver((strVal) -> {
                return this.getEnvironment().resolvePlaceholders(strVal);
            });
        }

        String[] weaverAwareNames = beanFactory
        .getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        String[] var3 = weaverAwareNames;
        int var4 = weaverAwareNames.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String weaverAwareName = var3[var5];
            this.getBean(weaverAwareName);
        }

        beanFactory.setTempClassLoader((ClassLoader)null);
        beanFactory.freezeConfiguration();
        beanFactory.preInstantiateSingletons();
    }

接下來調用finishRefresh()函數用於完成刷新後的一些掃尾工作,包括產生的緩存、初始化生命周期處理器LifecycleProcessor,並調用其onRefresh()方法、發布事件、調用LiveBeansView的registerApplicationContext註冊context。

    protected void finishRefresh() {
        this.clearResourceCaches();
        this.initLifecycleProcessor();
        this.getLifecycleProcessor().onRefresh();
        this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
        LiveBeansView.registerApplicationContext(this);
    }

接著看run函數,在刷新完context後,調用了一個afterRefresh函數,這個函數前面已經說過了,是為了給ApplicationContext的子類留下的一個擴展點。
然後調用了listeners.started(context);,把監聽器設置成了已經啟動的狀態。
最後調用了callRunners函數,獲取所有的ApplicationRunner和CommandLineRunner然後調用他們的run方法:

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

總結:spring boot 2.0在啟動的時候,首先會調用SpringApplication的構造函數進行初始化,調用實例函數run,在run函數中,首先獲取監聽器,並設置成啟動狀態,後面準備環境prepareEnvironment,準備prepareContext上下文,刷新上下文refreshContext,最後調用callRunners來依次調用註冊的Runner。

spring boot 2.0 源碼分析(五)