SpringBoot初始化流程,tomcatStarter调用

1,SpringBoot初始化

1, Springboot版本

Springboot版本 2.1.7.RELEASE

2, 文章主要解决的问题

1,主要看一下 ServletContainerInitializer 和 ServletContextInitializer 在Springboot中的使用, ServletContextInitializer 是如何在初始化时被调用的。
2, TomcatStart怎么将tomcat启动(ServletContainerInitailizer)与spring的ServletContextInitializer 绑定的

3, SpringApplication.run(SecurityApplication.class, args) 启动

   最后调用了AbstractApplicationContext的onRefresh方法,  这是一个抽象类。 onRefresh方式没有实现。<br />!

image.png

4, ServletWebServerApplicationContext继承了AbstractApplicationContext。


我用的SpringBoot版本是初始化时实际是调用了这个类里的onrefresh方法。
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
是后续调用ServletContextInitializer 的关键,
this.getSelfInitializer() 这里创建了一个ServletContextInitializer****匿名内部类, 相当于一个回调。

image.png

5, factory.getWebServer获取WebServer的工厂类

factory.getWebServer 获取WebServer的工厂实现。 我们使用的是tomcat
image.png

public WebServer getWebServer(ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();
      	.....
		// 这个类是关键 做一些准备工作
        this.prepareContext(tomcat.getHost(), initializers);
        return this.getTomcatWebServer(tomcat);
    }


 protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
        File documentRoot = this.getValidDocumentRoot();
        TomcatEmbeddedContext context = new TomcatEmbeddedContext();
        .....
        // 把ServletContextInitializer的实现都合并起来  [1]
        ServletContextInitializer[] initializersToUse = this.mergeInitializers(initializers);
        // 这个方法最重要的是把TomcatStarter添加到了tomcat容器ContextServletContainerInitializer集合中
      	// 容器创建完成后会遍历调用ContextServletContainerInitializer的onStartUp方法。
        this.configureContext(context, initializersToUse);
        this.postProcessContext(context);
    }

  protected void configureContext(Context context, ServletContextInitializer[] initializers) {
      	// [2]
        TomcatStarter starter = new TomcatStarter(initializers);
      //把TomcatStarter添加到了tomcat容器ContextServletContainerInitializer集合中
        context.addServletContainerInitializer(starter, NO_CLASSES);
	    .........
  }

[1] 处合并返回的 ServletContextInitializer[] initializersToUse
image.png
[2] 通过构造器的方式把[1]处获取的ServletContextInitializer[] 设置到了 TomcatStarter的属性值中。

**private final **ServletContextInitializer[] initializers;

在tomcat调用ServletContainerInitializer#onStartUp方法时TomcatStarter会遍历这三个实现类
注意第三个是ServletWebServerApplicationContext&lambda, 是通过this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});创建添加的。所以onStartUp调用的是this.getSelfInitializer()方法

6, TomcatStarter ServletContainerInitializer的实现类

class TomcatStarter implements ServletContainerInitializer {

   // ServletContextInitializer是Spring中维护的接口
    private final ServletContextInitializer[] initializers;

    TomcatStarter(ServletContextInitializer[] initializers) {
        this.initializers = initializers;
    }
// tomcat容器启动最后会调用这个方法,这是servlet3.0时添加的
    public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {
   
            ServletContextInitializer[] var3 = this.initializers;
            int var4 = var3.length;
		// 遍历执行ServletContextInitializer#onStartup
            for(int var5 = 0; var5 < var4; ++var5) {
                ServletContextInitializer initializer = var3[var5];
                initializer.onStartup(servletContext);
            }
 
    }
  1. TomcatStarter是ServletContainerInitializer的实现类。 tomcat容器在启动时会调用ServletContainerInitializer#onStartUp方法。
  2. TomcatStarter这里的ServletContextInitializer[]只有3个实现类。 其中有一个是this.webServer = factory.getWebServer(**new ServletContextInitializer[]{this.getSelfInitializer()}); 中的new **ServletContextInitializer[]{this.getSelfInitializer()}添加进的
  3. onStartUp方法会回调去执行ServletWebServerApplicationContext的selfInitialize方法
  private ServletContextInitializer getSelfInitializer() {
        return this::selfInitialize;
    }

    private void selfInitialize(ServletContext servletContext) throws ServletException {
        this.prepareWebApplicationContext(servletContext);
        this.registerApplicationScope(servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(this.getBeanFactory(), servletContext);
       // 获取ServletContextInitializerBeans
        Iterator var2 = this.getServletContextInitializerBeans().iterator();

        // 遍历去执行ServletContextInitializer#onStartup方法
        while(var2.hasNext()) {
            ServletContextInitializer beans = (ServletContextInitializer)var2.next();
            beans.onStartup(servletContext);
        }

    }

	// 获取ServletContextInitializerBeans并排序
    ServletContextInitializerBeans类
    @SafeVarargs
    public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class... initializerTypes) {
        this.initializerTypes = initializerTypes.length != 0 ? Arrays.asList(initializerTypes) : Collections.singletonList(ServletContextInitializer.class);
        this.addServletContextInitializerBeans(beanFactory);
        this.addAdaptableBeans(beanFactory);
        List<ServletContextInitializer> sortedInitializers = (List)this.initializers.values().stream().flatMap((value) -> {
            return value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE);
        }).collect(Collectors.toList());
        this.sortedList = Collections.unmodifiableList(sortedInitializers);
        this.logMappings(this.initializers);
    }

ServletContextInitializerBeans 从beanFactory中获取spring容器中所有的ServletContextInitializer实现(filter列表以及servlet都添加进去)
image.png

7, 总结

经过上面一系列的初始化, ServletContextInitializer在容器启动时就被成功调用了。
ServletContextInitializer的实现有很多
image.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值