springboot啟動(dòng)解析八

本章節(jié)繼續(xù)分析run方法的第15行代碼:

public ConfigurableApplicationContext run(String... args) {
        1.StopWatch stopWatch = new StopWatch();
        2.stopWatch.start();
        3.ConfigurableApplicationContext context = null;
        4.Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        5.configureHeadlessProperty();
        6.SpringApplicationRunListeners listeners = getRunListeners(args);
        7.listeners.starting();
        try {
        8.  ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
        9.  ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
        10. configureIgnoreBeanInfo(environment);
        11. Banner printedBanner = printBanner(environment);
        12. context = createApplicationContext();
        13. exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
        14.     prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
        15. refreshContext(context);
        16. afterRefresh(context, applicationArguments);
        17. stopWatch.stop();
        18. if (this.logStartupInfo) {
        19.     new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
        20. listeners.started(context);
        21. callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
        22. handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
        23. listeners.running(context);
        }
        catch (Throwable ex) {
        24. handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }
  • 其中第15行的代碼如下:
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

本章節(jié)主要分析:registerBeanPostProcessors癞蚕,initMessageSource,initApplicationEventMulticaster,onRefresh,registerListeners,finishBeanFactoryInitialization拖陆,finishRefresh,destroyBeans,cancelRefresh,resetCommonCaches

registerBeanPostProcessors

  • 具體代碼如下:registerBeanPostProcessors 本行代碼就是注冊(cè)BeanPostProcessors
    具體代碼如下:
public static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

        // Register BeanPostProcessorChecker that logs an info message when
        // a bean is created during BeanPostProcessor instantiation, i.e. when
        // a bean is not eligible for getting processed by all BeanPostProcessors.
        int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
        beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

        // Separate between BeanPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
        List<String> orderedPostProcessorNames = new ArrayList<>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
                priorityOrderedPostProcessors.add(pp);
                if (pp instanceof MergedBeanDefinitionPostProcessor) {
                    internalPostProcessors.add(pp);
                }
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        // First, register the BeanPostProcessors that implement PriorityOrdered.
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

        // Next, register the BeanPostProcessors that implement Ordered.
        List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
        for (String ppName : orderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            orderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, orderedPostProcessors);

        // Now, register all regular BeanPostProcessors.
        List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String ppName : nonOrderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            nonOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

        // Finally, re-register all internal BeanPostProcessors.
        sortPostProcessors(internalPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, internalPostProcessors);

        // Re-register post-processor for detecting inner beans as ApplicationListeners,
        // moving it to the end of the processor chain (for picking up proxies etc).
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    }

先加個(gè)BeanPostProcessorChecker懊亡,會(huì)在beanPostBean創(chuàng)建bean的時(shí)候 打印信息或者打印不合格的bean

  • 所以通過以上可知道 beanDeifion在BeanFactoryPostProcessor確定
  • beanPostProcessor確定最終的bean(因?yàn)閎ean在初始化結(jié)束前后可以獲取修改bean)
  • 查找 四種類型的beanPostProcessor 1.PriorityOrdered 2 Ordered 3 rest 4 internalPostProcessors
    其中internalPostProcessors 屬于PriorityOrdered 和Ordered 同時(shí)是MergedBeanDefinitionPostProcessor 主要是修改RootBeanDefinition
  • RootBeanDefinition 它可能來源于多個(gè)原始Bean定義(繼承自其他的bean定義依啰,通常被注冊(cè)為GenericBeanDefinitions)。RootBeanDefinition從本質(zhì)上將是運(yùn)行時(shí)統(tǒng)一的Bean定義視圖店枣。
    在配置階段速警,RootBeanDefinition也可能用于注冊(cè)獨(dú)立的bean定義。然而艰争,自從Spring2.5依賴坏瞄,編程地注冊(cè)bean定義建議使用 GenericBeanDefinition類。GenericBeanDefinition在允許動(dòng)態(tài)定義父依賴而不是硬編碼作為RootBeanDefinition方面有優(yōu)勢(shì)甩卓。
  • 然后依次注冊(cè) PriorityOrdered Ordered 注冊(cè)其他的
  • 最終在添加一個(gè)ApplicationListenerDetector鸠匀,其主要是檢測(cè)哪些bean是ApplicationListener

initMessageSource

這個(gè)是處理國(guó)際化的,具體代碼如下:

protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
            // Make MessageSource aware of parent MessageSource.
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    // Only set parent context as parent MessageSource if no parent MessageSource
                    // registered already.
                    hms.setParentMessageSource(getInternalParentMessageSource());
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Using MessageSource [" + this.messageSource + "]");
            }
        }
        else {
            // Use empty MessageSource to be able to accept getMessage calls.
            DelegatingMessageSource dms = new DelegatingMessageSource();
            dms.setParentMessageSource(getInternalParentMessageSource());
            this.messageSource = dms;
            beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
                        "': using default [" + this.messageSource + "]");
            }
        }
    }
  • 首先檢測(cè)是否存在messageSource的bean逾柿,若是存在獲取這個(gè)bean 然后 若是存在父容器缀棍,就設(shè)置該父容器的messageSource為當(dāng)前容器的父messageSource,如果父容器不存在messageSource机错,就設(shè)置父容器本身爬范。設(shè)置父messageSource的意義是當(dāng)messageSource無法解析就交給父messageSource
  • 若是不存在 設(shè)一個(gè)emtpymessageSource(DelegatingMessageSource ),繼續(xù)按照上述邏輯設(shè)置父MessageSource ,然后注冊(cè)該bean

initApplicationEventMulticaster 初始化容器的組播組件

  • beanFactory.containsLocalBean(beanName) 只會(huì)在當(dāng)前容器中查找對(duì)應(yīng)的beanName是否存在
protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                        "': using default [" + this.applicationEventMulticaster + "]");
            }
        }
    }
  • 上述方法主要是查看當(dāng)前beanName是否存在對(duì)應(yīng)的ApplicationEventMulticaster 弱匪,存在就注冊(cè)該bean 不存在就設(shè)置SimpleApplicationEventMulticaster為組播組件

onRefresh的代碼如下:

    protected void onRefresh() {
        super.onRefresh();
        try {
            createWebServer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start web server", ex);
        }
    }

public static ThemeSource initThemeSource(ApplicationContext context) {
        if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {
            ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);
            // Make ThemeSource aware of parent ThemeSource.
            if (context.getParent() instanceof ThemeSource && themeSource instanceof HierarchicalThemeSource) {
                HierarchicalThemeSource hts = (HierarchicalThemeSource) themeSource;
                if (hts.getParentThemeSource() == null) {
                    // Only set parent context as parent ThemeSource if no parent ThemeSource
                    // registered already.
                    hts.setParentThemeSource((ThemeSource) context.getParent());
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Using ThemeSource [" + themeSource + "]");
            }
            return themeSource;
        }
        else {
            // Use default ThemeSource to be able to accept getTheme calls, either
            // delegating to parent context's default or to local ResourceBundleThemeSource.
            HierarchicalThemeSource themeSource = null;
            if (context.getParent() instanceof ThemeSource) {
                themeSource = new DelegatingThemeSource();
                themeSource.setParentThemeSource((ThemeSource) context.getParent());
            }
            else {
                themeSource = new ResourceBundleThemeSource();
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +
                        "': using default [" + themeSource + "]");
            }
            return themeSource;
        }
    }
    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = getServletContext();
        if (webServer == null && servletContext == null) {
            ServletWebServerFactory factory = getWebServerFactory();
            this.webServer = factory.getWebServer(getSelfInitializer());
        }
        else if (servletContext != null) {
            try {
                getSelfInitializer().onStartup(servletContext);
            }
            catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context",
                        ex);
            }
        }
        initPropertySources();
    }


    protected void initPropertySources() {
        ConfigurableEnvironment env = getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
        }
    }

    protected ServletWebServerFactory getWebServerFactory() {
        // Use bean names so that we don't consider the hierarchy
        String[] beanNames = getBeanFactory()
                .getBeanNamesForType(ServletWebServerFactory.class);
        if (beanNames.length == 0) {
            throw new ApplicationContextException(
                    "Unable to start ServletWebServerApplicationContext due to missing "
                            + "ServletWebServerFactory bean.");
        }
        if (beanNames.length > 1) {
            throw new ApplicationContextException(
                    "Unable to start ServletWebServerApplicationContext due to multiple "
                            + "ServletWebServerFactory beans : "
                            + StringUtils.arrayToCommaDelimitedString(beanNames));
        }
        return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
    }
    public WebServer getWebServer(ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();
        File baseDir = (this.baseDirectory != null ? this.baseDirectory
                : createTempDir("tomcat"));
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        Connector connector = new Connector(this.protocol);
        tomcat.getService().addConnector(connector);
        customizeConnector(connector);
        tomcat.setConnector(connector);
        tomcat.getHost().setAutoDeploy(false);
        configureEngine(tomcat.getEngine());
        for (Connector additionalConnector : this.additionalTomcatConnectors) {
            tomcat.getService().addConnector(additionalConnector);
        }
        prepareContext(tomcat.getHost(), initializers);
        return getTomcatWebServer(tomcat);
    }


    protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
        File documentRoot = getValidDocumentRoot();
        TomcatEmbeddedContext context = new TomcatEmbeddedContext();
        if (documentRoot != null) {
            context.setResources(new LoaderHidingResourceRoot(context));
        }
        context.setName(getContextPath());
        context.setDisplayName(getDisplayName());
        context.setPath(getContextPath());
        File docBase = (documentRoot != null ? documentRoot
                : createTempDir("tomcat-docbase"));
        context.setDocBase(docBase.getAbsolutePath());
        context.addLifecycleListener(new FixContextListener());
        context.setParentClassLoader(
                this.resourceLoader != null ? this.resourceLoader.getClassLoader()
                        : ClassUtils.getDefaultClassLoader());
        resetDefaultLocaleMapping(context);
        addLocaleMappings(context);
        context.setUseRelativeRedirects(false);
        configureTldSkipPatterns(context);
        WebappLoader loader = new WebappLoader(context.getParentClassLoader());
        loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
        loader.setDelegate(true);
        context.setLoader(loader);
        if (isRegisterDefaultServlet()) {
            addDefaultServlet(context);
        }
        if (shouldRegisterJspServlet()) {
            addJspServlet(context);
            addJasperInitializer(context);
        }
        context.addLifecycleListener(new StaticResourceConfigurer(context));
        ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
        host.addChild(context);
        configureContext(context, initializersToUse);
        postProcessContext(context);
    }

public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
        Assert.notNull(tomcat, "Tomcat Server must not be null");
        this.tomcat = tomcat;
        this.autoStart = autoStart;
        initialize();
    }

    private void initialize() throws WebServerException {
        TomcatWebServer.logger
                .info("Tomcat initialized with port(s): " + getPortsDescription(false));
        synchronized (this.monitor) {
            try {
                addInstanceIdToEngineName();

                Context context = findContext();
                context.addLifecycleListener((event) -> {
                    if (context.equals(event.getSource())
                            && Lifecycle.START_EVENT.equals(event.getType())) {
                        // Remove service connectors so that protocol binding doesn't
                        // happen when the service is started.
                        removeServiceConnectors();
                    }
                });

                // Start the server to trigger initialization listeners
                this.tomcat.start();

                // We can re-throw failure exception directly in the main thread
                rethrowDeferredStartupExceptions();

                try {
                    ContextBindings.bindClassLoader(context, context.getNamingToken(),
                            getClass().getClassLoader());
                }
                catch (NamingException ex) {
                    // Naming is not enabled. Continue
                }

                // Unlike Jetty, all Tomcat threads are daemon threads. We create a
                // blocking non-daemon to stop immediate shutdown
                startDaemonAwaitThread();
            }
            catch (Exception ex) {
                stopSilently();
                throw new WebServerException("Unable to start embedded Tomcat", ex);
            }
        }
    }
  • 上述代碼主要是初始化ThemeSource青瀑,如果沒有就設(shè)置ResourceBundleThemeSource,整個(gè)邏輯類似于messageSource
  • 創(chuàng)建WebServer
  • 如果webServer和servletcontext都為null 則去獲取ServletWebServerFactory的bean
  • ServletContextInitializer 存在的作用主要是讓ServletContextInitializer 可以被spring容器管理 而不被servlet容器管理,且與WebApplicationInitializer不同的是 實(shí)現(xiàn)ServletContextInitializer 的實(shí)現(xiàn)類且未實(shí)現(xiàn)WebApplicationInitializer 不會(huì)被SpringServletContainerInitializer檢測(cè)到斥难,因此不會(huì)有servlet容器自動(dòng)引導(dǎo)枝嘶。其onStartup方法 主要是配置ServletContext,比如any servlets, filters, listeners context-params and attributes
  • WebApplicationInitializer 可以看做是Web.xml的替代哑诊,它是一個(gè)接口群扶。通過實(shí)現(xiàn)WebApplicationInitializer,在其中可以添加servlet镀裤,listener等竞阐,在加載Web項(xiàng)目的時(shí)候會(huì)加載這個(gè)接口實(shí)現(xiàn)類,從而起到web.xml相同的作用

SpringServletContainerInitializer作為ServletContainerInitializer的實(shí)現(xiàn)類暑劝,通過SPI機(jī)制骆莹,在web容器加載的時(shí)候會(huì)自動(dòng)的被調(diào)用。(這個(gè)類上還有一個(gè)注解@HandlesTypes担猛,它的作用是將感興趣的一些類注入到ServletContainerInitializerde)汪疮, 而這個(gè)類的方法又會(huì)掃描找到WebApplicationInitializer的實(shí)現(xiàn)類,調(diào)用它的onStartup方法毁习,從而起到啟動(dòng)web.xml相同的作用。

  • getWebServer 主要是設(shè)置設(shè)置和啟動(dòng)內(nèi)置tomcat 設(shè)置Connector (默認(rèn)Nio協(xié)議)customizeConnector調(diào)整Connector
  • prepareContext 就是設(shè)置host host內(nèi)部持有的是spring的TomcatEmbeddedContext
  • 最后獲取TomcatWebServer并初始化卖丸,即設(shè)置LifecycleListener并且啟動(dòng)tomcat

registerListeners

  • 主要是注冊(cè)ApplicationListener-當(dāng)容器初始化完成之后纺且,需要處理一些操作,比如一些數(shù)據(jù)的加載稍浆、初始化緩存载碌、特定任務(wù)的注冊(cè)等等。這個(gè)時(shí)候我們就可以使用Spring提供的ApplicationListener來進(jìn)行操作衅枫。
  • 然后發(fā)布earlyApplicationEvents

finishBeanFactoryInitialization

  • 設(shè)置beanFactory 的conversion service(其實(shí)作為JavaBeans PropertyEditors.的替代者 用來轉(zhuǎn)換屬性值)
  • 為嵌入值(例如注釋屬性)添加String解析器嫁艇。
  • 盡早初始化LoadTimeWeaverAware bean以允許盡早注冊(cè)其變換器。
  • 將temporary ClassLoader設(shè)置為null
  • 凍結(jié)所有的beanDefinition,不允許更改
  • 實(shí)例所有非懶加載的bean對(duì)象

finishRefresh

  • 清除上下文級(jí)資源緩存(例如來自掃描的ASM元數(shù)據(jù))弦撩。
  • 初始化容器的lifecycle processor 比如smartLifeCycle
  • 按照phase的大小依次啟動(dòng)lifecycle processor
  • 發(fā)送ContextRefreshedEvent時(shí)間
  • 如果LiveBeansView MBean 激活了步咪,則參與LiveBeansView MBean。

destroyBeans 摧毀所有的單例

cancelRefresh 設(shè)active標(biāo)識(shí)為false

resetCommonCaches

  • 清除反射的緩存
  • 清除注解的相關(guān)緩存
  • Clear the internal {@code ResolvableType}/{@code SerializableTypeWrapper} cache.
  • 清除classloader緩存

內(nèi)置tomcat的說明

內(nèi)置tomcat的懸疑
首先創(chuàng)建ServletWebServerFactory的bean
然后調(diào)用其getWebServer生成WebServer
然后在創(chuàng)建baseDir益楼,根據(jù)協(xié)議創(chuàng)建Connector和ProtocolHandler(協(xié)議處理器)
這個(gè)ProtocolHandler主要是設(shè)置adapter和Endpoint猾漫,而 adapter可以調(diào)用connector
adapter提供了service,prepare感凤,asyncDispatch悯周,log,checkRecycled陪竿,getDomain
其中domain是用來注冊(cè)跟這個(gè)connector關(guān)聯(lián)的Mbeans
然后創(chuàng)建service禽翼,connector,container(enigne),添加valve
下面關(guān)鍵的就來了 我們知道container的順序是engine闰挡,host锐墙,context,wrapper
我們這邊創(chuàng)建了一個(gè)TomcatEmbeddedContext解总,將spring容器塞入TomcatEmbeddedContext
同時(shí)創(chuàng)建一個(gè)WebappLoader給當(dāng)前的TomcatEmbeddedContext
創(chuàng)建一個(gè)Wrapper塞入TomcatEmbeddedContext
通過把我們spring容器包裝成ServletContextInitializer
然后配置我們的context 包括設(shè)置starter(其就是我們ServletContextInitializer的集合類)
設(shè)置Valve,ErrorPage,MimeMappings
然后我們啟動(dòng)tomcat(啟動(dòng)server)
最終我們調(diào)用ServletWebServerApplicationContext的selfInitialize贮匕,其主要是把spring容器
和servletContext 互相綁定,當(dāng)我們請(qǐng)求時(shí)候tomcat最終會(huì)調(diào)用dispatchServlet花枫,然后把spring容器設(shè)置
為該servlet的屬性刻盐,這樣就可以在該servlet使用spring提供的功能

ProtocolHandler 內(nèi)部包含一個(gè)endpoint 也就是說該協(xié)議采用
endpoint 進(jìn)行底層的socket的通信
可以把Endpoint理解 為netty的serverbootStrap

當(dāng)endpoint發(fā)現(xiàn)需要處理的socket,會(huì)創(chuàng)建一個(gè)SocketProcessor
最終會(huì)調(diào)用ProtocolHandler的process方法劳翰,該方法會(huì)創(chuàng)建一個(gè)Processor
該P(yáng)rocessor會(huì)包含adapter敦锌,其他的請(qǐng)求信息等
最終adapter會(huì)交給對(duì)應(yīng)的container

--
Valve和ContainerBackgroundProcessor
一般只會(huì)給engine啟動(dòng)一個(gè)線程去執(zhí)行ContainerBackgroundProcessor
而該任務(wù)會(huì)執(zhí)行當(dāng)前container和其子類容器的 backgroundProcess();
而 一般container的backgroundProcess不僅僅包含container本身還包含該
container的pipeline的valve的backgroundProcess

一般接受一個(gè)請(qǐng)求的流程是
Endpoint.Acceptor的acceptor線程接受到請(qǐng)求
一層層處理交給Adapter
而Adapter主要就是調(diào)用其service方法把
org.apache.coyote.Request req, org.apache.coyote.Response res
轉(zhuǎn)換為HttpServletRequest和HttpServletResponse
然后交給engine的第一個(gè)valve處理

每個(gè)容器都有一個(gè)pipeline 里面存儲(chǔ)鏈表valve
其最后一個(gè)valve都是負(fù)責(zé)連接下一個(gè)container

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市佳簸,隨后出現(xiàn)的幾起案子乙墙,更是在濱河造成了極大的恐慌,老刑警劉巖生均,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件听想,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡马胧,警方通過查閱死者的電腦和手機(jī)汉买,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佩脊,“玉大人蛙粘,你說我怎么就攤上這事⊥茫” “怎么了出牧?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)歇盼。 經(jīng)常有香客問我舔痕,道長(zhǎng),這世上最難降的妖魔是什么旺遮? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任赵讯,我火速辦了婚禮,結(jié)果婚禮上耿眉,老公的妹妹穿的比我還像新娘边翼。我一直安慰自己,他們只是感情好鸣剪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布组底。 她就那樣靜靜地躺著丈积,像睡著了一般。 火紅的嫁衣襯著肌膚如雪债鸡。 梳的紋絲不亂的頭發(fā)上江滨,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音厌均,去河邊找鬼唬滑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛棺弊,可吹牛的內(nèi)容都是我干的晶密。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼模她,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼稻艰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侈净,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤尊勿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后畜侦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體元扔,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年旋膳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了摇展。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡溺忧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盯孙,到底是詐尸還是另有隱情鲁森,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布振惰,位于F島的核電站歌溉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏骑晶。R本人自食惡果不足惜痛垛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桶蛔。 院中可真熱鬧匙头,春花似錦、人聲如沸仔雷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至电抚,卻和暖如春惕稻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝙叛。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工俺祠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人借帘。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓蜘渣,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親姻蚓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宋梧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1.1 Spring IoC容器和bean簡(jiǎn)介 本章介紹了Spring Framework實(shí)現(xiàn)的控制反轉(zhuǎn)(IoC)...
    起名真是難閱讀 2,584評(píng)論 0 8
  • 1.1 spring IoC容器和beans的簡(jiǎn)介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,717評(píng)論 2 22
  • Spring容器高層視圖 Spring 啟動(dòng)時(shí)讀取應(yīng)用程序提供的Bean配置信息狰挡,并在Spring容器中生成一份相...
    Theriseof閱讀 2,815評(píng)論 1 24
  • 本來是準(zhǔn)備看一看Spring源碼的捂龄。然后在知乎上看到來一個(gè)帖子,說有一群**自己連Spring官方文檔都沒有完全讀...
    此魚不得水閱讀 6,935評(píng)論 4 21
  • 最近這幾天加叁,都在練邏輯思維……不要太浮躁……不要太浮躁……不要太浮躁…… 看看余姚的變化倦沧,同一個(gè)老師,為什么差別那...
    小小小grow閱讀 160評(píng)論 0 0