zoukankan      html  css  js  c++  java
  • 【SpringBoot】 使用外部Tomcat方法及启动原理

    SpringBoot 使用外部Tomcat方法及启动原理

    基于 SpringBoot 2.x

    方法

    • 一、必须是一个war项目,利用IDEA可以直接创建,或者是修改pom.xml文件
    <packaging>war</packaging>
     
    • 1
    • 二、将内置Tomcat的作用范围修改成provided
    dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-tomcat</artifactId>
       <scope>provided</scope>
    </dependency>
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 三、自定义一个类继承 SpringBootServletInitializer 重写其configure()方法
    public class ServletInitializer extends SpringBootServletInitializer {
    
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            // 传入SpringBoot的主程序类
            return builder.sources(SbdemoApplication.class);
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    启动原理

    前提

    • 根据Servlet3.0规范,服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面ServletContainerInitializer实例。
    • ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下,有一个名为javax.servlet.ServletContainerInitializer的文件,内容就是ServletContainerInitializer的实现类的全类名。
    • 使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类。

    SpringBoot中启动流程

    • 一、SpringBoot 中的 ServletContainerInitializer 实现类位置在spring-web模块下
      这里写图片描述
      文件内容:
    org.springframework.web.SpringServletContainerInitializer
     
    • 1
    • 二、SpringServletContainerInitializer类
    @HandlesTypes({WebApplicationInitializer.class})
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        public SpringServletContainerInitializer() {
        }
    
        public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
            List<WebApplicationInitializer> initializers = new LinkedList();
            Iterator var4;
            if (webAppInitializerClasses != null) {
                var4 = webAppInitializerClasses.iterator();
    
                while(var4.hasNext()) {
                    Class<?> waiClass = (Class)var4.next();
                    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                        try {
                            // 将@HandlesTypes(WebApplicationInitializer.class)标注的所有这个类型的类都传入到onStartup方法的Set<Class<?>>;为这些WebApplicationInitializer类型的类创建实例。
                            initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());
                        } catch (Throwable var7) {
                            throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
                        }
                    }
                }
            }
    
            if (initializers.isEmpty()) {
                servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
            } else {
                servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
                AnnotationAwareOrderComparator.sort(initializers);
                var4 = initializers.iterator();
    
                while(var4.hasNext()) {
                    WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
                    // 每一个WebApplicationInitializer都调用自己的onStartup()
                    initializer.onStartup(servletContext);
                }
            }
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 三、Tomcat 启动引导类
    // ServletInitializer 继承 SpringBootServletInitializer
    public class ServletInitializer extends SpringBootServletInitializer {
    
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            return builder.sources(SbdemoApplication.class);
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    SpringBootServletInitializer 继承 WebApplicationInitializer 类,就是SpringServletContainerInitializer类的@HandlesTypes({WebApplicationInitializer.class}), 下面展示的是 onStartup() 、createRootApplicationContext() 和 configure() 方法

    public abstract class SpringBootServletInitializer implements WebApplicationInitializer {
        public void onStartup(ServletContext servletContext) throws ServletException {
            this.logger = LogFactory.getLog(this.getClass());
            // 创建web应用容器
            WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
            if (rootAppContext != null) {
                servletContext.addListener(new ContextLoaderListener(rootAppContext) {
                    public void contextInitialized(ServletContextEvent event) {
                    }
                });
            } else {
                this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
            }
    
        }
    
        protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
            // 1、创建SpringApplicationBuilder
            SpringApplicationBuilder builder = this.createSpringApplicationBuilder();
            StandardServletEnvironment environment = new StandardServletEnvironment();
            // 2、准备环境
            environment.initPropertySources(servletContext, (ServletConfig)null);
            builder.environment(environment);
            builder.main(this.getClass());
            ApplicationContext parent = this.getExistingRootWebApplicationContext(servletContext);
            if (parent != null) {
                this.logger.info("Root context already created (using as parent).");
                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)null);
                builder.initializers(new ApplicationContextInitializer[]{new ParentContextApplicationContextInitializer(parent)});
            }
            // 3、初始化
            builder.initializers(new ApplicationContextInitializer[]{new ServletContextApplicationContextInitializer(servletContext)});
            builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
            // 4、调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来
            builder = this.configure(builder);
    
            SpringApplication application = builder.build();
            if (application.getAllSources().isEmpty() && AnnotationUtils.findAnnotation(this.getClass(), Configuration.class) != null) {
                application.addPrimarySources(Collections.singleton(this.getClass()));
            }
    
            Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation");
            if (this.registerErrorPageFilter) {
                application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
            }
            // 5、启动Spring应用
            return this.run(application);
        }
    }
    
    // 此方法被启动引导类 ServletInitializer有方法重写, 传入的是应用构建器SpringApplicationBuilder, 也就是SpringBoot的主程序类
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
            return builder;
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    原文连接: https://blog.csdn.net/qq_34560242/article/details/80394266

  • 相关阅读:
    Python神库分享之geoip2 IP定位库
    科普一下推荐引擎
    浏览器插件之王-Tampermonkey(油猴脚本)
    Swagger入门教程
    使用SonarQube+Eclipse来分析python代码
    什么是搜索引擎蜘蛛?
    让所有网站都提供API的Python库:Toapi
    如何提高自己的逻辑思维能力?
    推荐系统和搜索引擎的关系
    html 后台页面布局
  • 原文地址:https://www.cnblogs.com/h--d/p/14797680.html
Copyright © 2011-2022 走看看