当前位置: 移动技术网 > IT编程>开发语言>Java > Springboot 2使用外部Tomcat源码分析

Springboot 2使用外部Tomcat源码分析

2019年08月17日  | 移动技术网IT编程  | 我要评论

springboot 使用外部 tomcat

1.修改 pom.xml,改为打 war 包
<packaging>war</packaging>
2.将 springboot 内置 tomcat 作用域改为provided

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-tomcat</artifactid>
    <scope>provided</scope>
</dependency>

3.重写 springbootservletinitializer

@springbootapplication
public class bootstrap extends springbootservletinitializer {
  public static void main(string[] args) {
    springapplication.run(bootstrap.class, args);
  }

  @override
  protected springapplicationbuilder configure(springapplicationbuilder builder) {
    return builder.sources(bootstrap.class);
  }
}

4.maven 打包出 war 包后,放到 tomcat 的 webapps 目录下即可。

如果要访问该 war 包的接口,默认需要在 url 加项目名作为前缀,例如:http://localhost:8080/{项目名}/users/123456

原理分析

servletcontainerinitializer

servlet 容器启动时,会扫描当前应用每个 jar 包路径meta-inf\services下的文件javax.servlet.servletcontainerinitializer,其文件内容就是 servletcontainerinitializer 的实现类全类名,并调用其 onstartup() 方法。比如,在 spring-web 包下,该文件内容就是org.springframework.web.springservletcontainerinitializer,其源码如下:

// 容器启动时,将 webapplicationinitializer 的所有子类传递至 webappinitializerclasses
@handlestypes(webapplicationinitializer.class)
public class springservletcontainerinitializer implements servletcontainerinitializer {
    /**
     * @param webappinitializerclasses @handlestypes 导入的类
     * @param servletcontext 当前 web 应用 servlet 上下文
     */
    @override
    public void onstartup(@nullable set<class<?>> webappinitializerclasses, servletcontext servletcontext) throws servletexception {
        list<webapplicationinitializer> initializers = new linkedlist<>();
        for (class<?> waiclass : webappinitializerclasses) {
            // 过滤出可用的 webapplicationinitializer
            if (!waiclass.isinterface() && !modifier.isabstract(waiclass.getmodifiers()) && webapplicationinitializer.class.isassignablefrom(waiclass)) {
                initializers.add((webapplicationinitializer)reflectionutils.accessibleconstructor(waiclass).newinstance());
            }
        }
        for (webapplicationinitializer initializer : initializers) {
            initializer.onstartup(servletcontext);
        }
    }
}

容器启动时,执行 springservletcontainerinitializer.onstartup() 方法,@handlestypes 注解声明了 webapplicationinitializer 的所有子类(在前面的示例中,启动类 bootstrap 实现的 springbootservletinitializer 就是它的一个实现)会被传递给方法的参数 webappinitializerclasses。

onstartup() 方法会过滤出 webappinitializerclasses 中可用的 webapplicationinitializer 子类 bootstrap,然后回调 springbootservletinitializer 的 onstartup() 方法,其源码如下:

public void onstartup(servletcontext servletcontext) throws servletexception {
    webapplicationcontext rootappcontext = createrootapplicationcontext(servletcontext);
}
protected webapplicationcontext createrootapplicationcontext(servletcontext servletcontext) {
    springapplicationbuilder builder = createspringapplicationbuilder();
    // 指定主类 bootstrap
    builder.main(getclass());
    // 回调 bootstrap 重写的方法
    builder = configure(builder);
    return run(builder.build());
}

这个方法会配置当前 web 应用程序上下文环境:指定主类、注册 servletcontext、调用 configure()、run 运行。

由于 bootstrap 重写了 configure(),所以会执行重写的方法来指定主类,最后通过 run 来完成启动 springboot 应用。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网