spring boot中servlet启动原理详解编程语言

启动过程及原理

1 spring boot 应用启动运行run方法

StopWatch stopWatch = new StopWatch(); 
        stopWatch.start(); 
        ConfigurableApplicationContext context = null; 
        FailureAnalyzers analyzers = null; 
        configureHeadlessProperty(); 
        SpringApplicationRunListeners listeners = getRunListeners(args); 
        listeners.starting(); 
        try { 
            ApplicationArguments applicationArguments = new DefaultApplicationArguments( 
                    args); 
            ConfigurableEnvironment environment = prepareEnvironment(listeners, 
                    applicationArguments); 
            Banner printedBanner = printBanner(environment); 
                       //创建一个ApplicationContext容器 
            context = createApplicationContext(); 
            analyzers = new FailureAnalyzers(context); 
            prepareContext(context, environment, listeners, applicationArguments, 
                    printedBanner); 
                      //刷新IOC容器 
            refreshContext(context); 
            afterRefresh(context, applicationArguments); 
            listeners.finished(context, null); 
            stopWatch.stop(); 
            if (this.logStartupInfo) { 
                new StartupInfoLogger(this.mainApplicationClass) 
                        .logStarted(getApplicationLog(), stopWatch); 
            } 
            return context; 
        } 
        catch (Throwable ex) { 
            handleRunFailure(context, listeners, analyzers, ex); 
            throw new IllegalStateException(ex); 
        }     

 

2  createApplicationContext():创建IOC容器,如果是web应用则创建AnnotationConfigEmbeddedWebApplacation的IOC容器,如果不是,则创建AnnotationConfigApplication的IOC容器

    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context." 
            + "annotation.AnnotationConfigApplicationContext"; 
 
    /** 
     * The class name of application context that will be used by default for web 
     * environments. 
     */ 
    public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework." 
            + "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext"; 
 
 
protected ConfigurableApplicationContext createApplicationContext() { 
        Class<?> contextClass = this.applicationContextClass; 
        if (contextClass == null) { 
            try {
          //根据应用环境,创建不同的IOC容器 contextClass
= Class.forName(this.webEnvironment ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS); } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass); }

3    refreshContext(context) spring boot刷新IOC容器(创建容器对象,并初始化容器,创建容器每一个组件)

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

4 refresh(context);刷新刚才创建的IOC容器

protected void refresh(ApplicationContext applicationContext) { 
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); 
        ((AbstractApplicationContext) applicationContext).refresh(); 
    }

5 调用父类的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(); 
            } 
 
        } 
    }

6  抽象父类AbstractApplicationContext类的子类EmbeddedWebApplicationContext的onRefresh方法

@Override 
    protected void onRefresh() { 
        super.onRefresh(); 
        try { 
            createEmbeddedServletContainer(); 
        } 
        catch (Throwable ex) { 
            throw new ApplicationContextException("Unable to start embedded container", 
                    ex); 
        } 
    }

7  在createEmbeddedServletContainer放啊发中会获取嵌入式Servlet容器工厂,由容器工厂创建Servlet

private void createEmbeddedServletContainer() { 
        EmbeddedServletContainer localContainer = this.embeddedServletContainer; 
        ServletContext localServletContext = getServletContext(); 
        if (localContainer == null && localServletContext == null) {
                //获取嵌入式Servlet容器工厂 EmbeddedServletContainerFactory containerFactory
= getEmbeddedServletContainerFactory();
          //根据容器工厂获取对应嵌入式Servlet容器
this.embeddedServletContainer = containerFactory .getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) { try { getSelfInitializer().onStartup(localServletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } initPropertySources(); }

8  从IOC容器中获取Servlet容器工厂

//EmbeddedWebApplicationContext#getEmbeddedServletContainerFactory   
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {   
    // Use bean names so that we don't consider the hierarchy   
    String[] beanNames = getBeanFactory()   
        .getBeanNamesForType(EmbeddedServletContainerFactory.class);   
    if (beanNames.length == 0) {   
        throw new ApplicationContextException(   
            "Unable to start EmbeddedWebApplicationContext due to missing "   
            + "EmbeddedServletContainerFactory bean.");   
    }   
    if (beanNames.length > 1) {   
        throw new ApplicationContextException(   
            "Unable to start EmbeddedWebApplicationContext due to multiple "   
            + "EmbeddedServletContainerFactory beans : "   
            + StringUtils.arrayToCommaDelimitedString(beanNames));   
    }   
    return getBeanFactory().getBean(beanNames[0],   
                                    EmbeddedServletContainerFactory.class);   
}  

 

9  使用Servlet容器工厂获取嵌入式Servlet容器,具体使用哪一个容器工厂看配置环境依赖

this.embeddedServletContainer = containerFactory   
            .getEmbeddedServletContainer(getSelfInitializer());  

10  上述创建过程  首先启动IOC容器,接着启动嵌入式Servlet容器,接着将IOC容器中剩下没有创建的对象获取出来,比如自己创建的controller

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

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { 
        // Initialize conversion service for this context. 
        if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && 
                beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { 
            beanFactory.setConversionService( 
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); 
        } 
 
        // Register a default embedded value resolver if no bean post-processor 
        // (such as a PropertyPlaceholderConfigurer bean) registered any before: 
        // at this point, primarily for resolution in annotation attribute values. 
        if (!beanFactory.hasEmbeddedValueResolver()) { 
            beanFactory.addEmbeddedValueResolver(new StringValueResolver() { 
                @Override 
                public String resolveStringValue(String strVal) { 
                    return getEnvironment().resolvePlaceholders(strVal); 
                } 
            }); 
        } 
 
        // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. 
        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); 
        for (String weaverAwareName : weaverAwareNames) { 
            getBean(weaverAwareName); 
        } 
 
        // Stop using the temporary ClassLoader for type matching. 
        beanFactory.setTempClassLoader(null); 
 
        // Allow for caching all bean definition metadata, not expecting further changes. 
        beanFactory.freezeConfiguration(); 
 
        // Instantiate all remaining (non-lazy-init) singletons. 
        beanFactory.preInstantiateSingletons(); 
    }

 

看看 preInstantiateSingletons方法

public void preInstantiateSingletons() throws BeansException { 
        if (this.logger.isDebugEnabled()) { 
            this.logger.debug("Pre-instantiating singletons in " + this); 
        } 
 
        List<String> beanNames = new ArrayList(this.beanDefinitionNames); 
        Iterator var2 = beanNames.iterator(); 
 
        while(true) { 
            while(true) { 
                String beanName; 
                RootBeanDefinition bd; 
                do { 
                    do { 
                        do { 
                            if (!var2.hasNext()) { 
                                var2 = beanNames.iterator(); 
 
                                while(var2.hasNext()) { 
                                    beanName = (String)var2.next(); 
                                    Object singletonInstance = this.getSingleton(beanName); 
                                    if (singletonInstance instanceof SmartInitializingSingleton) { 
                                        final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance; 
                                        if (System.getSecurityManager() != null) { 
                                            AccessController.doPrivileged(new PrivilegedAction<Object>() { 
                                                public Object run() { 
                                                    smartSingleton.afterSingletonsInstantiated(); 
                                                    return null; 
                                                } 
                                            }, this.getAccessControlContext()); 
                                        } else { 
                                            smartSingleton.afterSingletonsInstantiated(); 
                                        } 
                                    } 
                                } 
 
                                return; 
                            } 
 
                            beanName = (String)var2.next(); 
                            bd = this.getMergedLocalBeanDefinition(beanName); 
                        } while(bd.isAbstract()); 
                    } while(!bd.isSingleton()); 
                } while(bd.isLazyInit()); 
 
                if (this.isFactoryBean(beanName)) { 
                    final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName); 
                    boolean isEagerInit; 
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { 
                        isEagerInit = ((Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 
                            public Boolean run() { 
                                return ((SmartFactoryBean)factory).isEagerInit(); 
                            } 
                        }, this.getAccessControlContext())).booleanValue(); 
                    } else { 
                        isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit(); 
                    } 
 
                    if (isEagerInit) { 
                        this.getBean(beanName); 
                    } 
                } else {
            //注册bean
this.getBean(beanName); } } } }

是使用getBean方法来通过反射将所有未创建的实例创建出来

  使用嵌入式Servlet容器:

     优点:   简单,便携

     缺点:   默认不支持jsp,优化定制比较复杂

使用外置Servlet容器的步骤:

  1  必须创建war项目,需要剑豪web项目的目录结构

  2  嵌入式Tomcat依赖scope指定provided

  3  编写SpringBootServletInitializer类子类,并重写configure方法

public class ServletInitializer extends SpringBootServletInitializer {   
   
    @Override   
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {   
        return application.sources(SpringBoot04WebJspApplication.class);   
    }   
} 

 

       4  启动服务器

jar包和war包启动区别

    jar包:执行SpringBootApplication的run方法,启动IOC容器,然后创建嵌入式Servlet容器

 war包:  先是启动Servlet服务器,服务器启动Springboot应用(springBootServletInitizer),然后启动IOC容器

Servlet 3.0+规则

    1  服务器启动(web应用启动),会创建当前web应用里面所有jar包里面的ServletContainerlnitializer实例

     2 ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下

   3  [email protected],在应用启动的时候加载指定的类。

外部Tomcat流程以及原理

  ①  启动Tomcat

  ②  根据上述描述的Servlet3.0+规则,可以在Spring的web模块里面找到有个文件名为javax.servlet.ServletContainerInitializer的文件,而文件的内容为org.springframework.web.SpringServletContainerInitializer,用于加载SpringServletContainerInitializer类

  ③看看SpringServletContainerInitializer定义

@HandlesTypes(WebApplicationInitializer.class) 
public class SpringServletContainerInitializer implements ServletContainerInitializer { 
/** 
* Delegate the [email protected] ServletContext} to any [email protected] WebApplicationInitializer} 
* implementations present on the application classpath. 
* <p>Because this class declares @[email protected] HandlesTypes(WebApplicationInitializer.class)}, 
* Servlet 3.0+ containers will automatically scan the classpath for implementations 
* of Spring's [email protected] WebApplicationInitializer} interface and provide the set of all 
* such types to the [email protected] webAppInitializerClasses} parameter of this method. 
* <p>If no [email protected] WebApplicationInitializer} implementations are found on the classpath, 
* this method is effectively a no-op. An INFO-level log message will be issued notifying 
* the user that the [email protected] ServletContainerInitializer} has indeed been invoked but that 
* no [email protected] WebApplicationInitializer} implementations were found. 
* <p>Assuming that one or more [email protected] WebApplicationInitializer} types are detected, 
* they will be instantiated (and <em>sorted</em> if the @[email protected] 
* org.springframework.core.annotation.Order @Order} annotation is present or 
* the [email protected] org.springframework.core.Ordered Ordered} interface has been 
* implemented). Then the [email protected] WebApplicationInitializer#onStartup(ServletContext)} 
* method will be invoked on each instance, delegating the [email protected] ServletContext} such 
* that each instance may register and configure servlets such as Spring's 
* [email protected] DispatcherServlet}, listeners such as Spring's [email protected] ContextLoaderListener}, 
* or any other Servlet API componentry such as filters. 
* @param webAppInitializerClasses all implementations of 
* [email protected] WebApplicationInitializer} found on the application classpath 
* @param servletContext the servlet context to be initialized 
* @see WebApplicationInitializer#onStartup(ServletContext) 
* @see AnnotationAwareOrderComparator 
*/ 
@Override 
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) 
throws ServletException { 
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>(); 
if (webAppInitializerClasses != null) { 
for (Class<?> waiClass : webAppInitializerClasses) { 
// Be defensive: Some servlet containers provide us with invalid classes, 
// no matter what @HandlesTypes says... 
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && 
WebApplicationInitializer.class.isAssignableFrom(waiClass)) { 
try {
                //为所有的WebApplicationInitializer类型创建实例,并加入集合中 initializers.add((WebApplicationInitializer) waiClass.newInstance()); }
catch (Throwable ex) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } } if (initializers.isEmpty()) { servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); return; } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers);
      //调用每一个WebApplicationInitializer实例的onstartup方法
for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); } } }

 在上面一段长长的注释中可以看到,[email protected](WebApplicationInitializer.class)标注的所有WebApplicationInitializer这个类型的类都传入到onStartup方法的Set参数中,并通过反射为这些WebApplicationInitializer类型的类创建实例;

  ④  方法最后,每一个WebApplicationInitilizer实现调用自己onstartup方法

  ⑤  而WebApplicationInitializer有个抽象实现类SpringBootServletInitializer(记住我们继承了该抽象类),则会调用每一个WebApplicationInitializer实例(包括SpringBootServletInitializer)的onStartup方法:

public abstract class SpringBootServletInitializer implements WebApplicationInitializer {   
//other code...   
       
@Override   
public void onStartup(ServletContext servletContext) throws ServletException {   
// Logger initialization is deferred in case a ordered   
// LogServletContextInitializer is being used   
this.logger = LogFactory.getLog(getClass());   
//创建IOC容器   
WebApplicationContext rootAppContext = createRootApplicationContext(   
servletContext);   
if (rootAppContext != null) {   
servletContext.addListener(new ContextLoaderListener(rootAppContext) {   
@Override   
public void contextInitialized(ServletContextEvent event) {   
// no-op because the application context is already initialized   
                }   
});   
}   
else {   
this.logger.debug("No ContextLoaderListener registered, as "   
+ "createRootApplicationContext() did not "   
+ "return an application context");   
}   
}   
protected WebApplicationContext createRootApplicationContext(   
ServletContext servletContext) {   
//创建Spring应用构建器,并进行相关属性设置   
SpringApplicationBuilder builder = createSpringApplicationBuilder();   
StandardServletEnvironment environment = new StandardServletEnvironment();   
environment.initPropertySources(servletContext, null);   
builder.environment(environment);   
builder.main(getClass());   
ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);   
if (parent != null) {   
this.logger.info("Root context already created (using as parent).");   
servletContext.setAttribute(   
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);   
builder.initializers(new ParentContextApplicationContextInitializer(parent));   
}   
builder.initializers(   
new ServletContextApplicationContextInitializer(servletContext));   
builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);   
//调用configure方法,创建war类型的web项目后,由于编写SpringBootServletInitializer的子类重写configure方法,所以此处调用的是我们定义的子类重写的configure方法   
builder = configure(builder);   
//通过构建器构建了一个Spring应用   
SpringApplication application = builder.build();   
if (application.getSources().isEmpty() && AnnotationUtils   
.findAnnotation(getClass(), Configuration.class) != null) {   
application.getSources().add(getClass());   
}   
Assert.state(!application.getSources().isEmpty(),   
"No SpringApplication sources have been defined. Either override the "   
+ "configure method or add an @Configuration annotation");   
// Ensure error pages are registered   
if (this.registerErrorPageFilter) {   
application.getSources().add(ErrorPageFilterConfiguration.class);   
}   
//启动Spring应用   
return run(application);   
}   
//Spring应用启动,创建并返回IOC容器   
protected WebApplicationContext run(SpringApplication application) {   
return (WebApplicationContext) application.run();   
}   
} 

   SpringBootServletInitializer实例执行onStartup方法的时候会通过createRootApplicationContext方法来执行run方法,接下来的过程就同以jar包形式启动的应用的run过程一样了,在内部会创建IOC容器并返回,只是以war包形式的应用在创建IOC容器过程中,不再创建Servlet容器了。

原文地址:http://www.cnblogs.com/developerxiaofeng/p/9081689.html

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/16226.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论