web容器启动Spring应用程序原理,@HandlesTypes与ServletContainerInitializer

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。web容器启动Spring应用程序原理,@HandlesTypes与ServletContainerInitializer,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

查看Spring源码发现有如下东西:
在这里插入图片描述

ServletContainerInitializer接口

在这里插入图片描述
首先我们要知道这是个Java EE规范中的接口,由具体的Servlet容器来实现,在Web容器启动时被回调。

作用

类似于一个监听容器启动的监听器。

用法

在实现该接口后,需要在SPI文件中注册,在Servlet容器启动时通过SPI从classpath下查找其实现类,实例化后进行回调。
在这里插入图片描述

举例

Spring的实现类
在这里插入图片描述

那实现类上标注了@HandlesTypes注解又是干嘛的呢?

@HandlesTypes注解

在这里插入图片描述

含义

这也是Java EE规范中的注解,表示当前ServletContainerInitializer的实现类,能处理的类型。这两个都是Servlet3.0中的东西。

主要作用

Servlet容器(例如tomcat)启动时,会将SPI注册的Java EE接口ServletContainerInitializer的所有的实现类(例如,SpringServletContainerInitializer)挨个回调其onStartup方法。

而onStartup方法是需要参数的,这时@HandlesTypes就派上用场了。

onStartup方法所需要的参数就通过@HandlesTypes注解传入。

实现原理

@HandlesTypes注解由Servlet容器提供支持(实现),参数中指定的所有实现类,利用字节码扫描框架(例如ASM、BCEL)从classpath中扫描出来,放入集合,传给回调方法onStartup的第一个参数。

言归正传,为什么Spring需要用到这部分注解?

我们总是能在传统的Spring项目看到如下Web容器配置文件。
在这里插入图片描述
为什么Spring项目中没有web配置文件?

通过创建Web初始化类,继承自AbstractAnnotationConfigDispatcherServletInitializer

去除web.xml配置文件的实现原理就得依靠Java EE提供的@HandlesTypes与ServletContainerInitializer了。

因此,Spring中使用该注解和接口的原因之一就是去除配置文件。

Spring去除配置文件的实现原理

有请看@HandlesTypes中参数WebApplicationInitializer的某个Spring-webmvc中的实现类:AbstractDispatcherServletInitializer。
在这里插入图片描述

注意:如果是SpringBoot项目这里就是唯一容器上下文。如果项目是SpringMVC+Spring,这里创建的上下文是Spring容器的子上下文,组成父子上下文。父子上下文特点是子容器(controller层)可访问父容器(service层,dao层)里的Bean,父容器不能访问子容器里的Bean,优点是层次分明。像是这种父子结构的容器,在@Service层是不能注入@Controller Bean的,原因如上。

因此我们得出结论,spring是通过代码中配置从而去除的web配置文件。

启动流程

假设Servlet容器是tomcat。

  1. 由tomcat在启动时根据SPI机制的ServiceLoader#load方法拿到所有JavaEE接口(ServletContainerInitializer)注册的实现类。
  2. Spring对该接口的实现类是SpringServletContainerInitializer,其类上标注了@HandlesTypes({WebApplicationInitializer.class})。
  3. tomcat从classpath下找到所有的WebApplicationInitializer实现类,将所有的实现类传入SpringServletContainerInitializer#onStartup方法的第一个参数,调用方法。
  4. 回到SpringServletContainerInitializer#onStartup方法中的逻辑,将所有的WebApplicationInitializer实现类的onStartup方法一一调用。
  5. WebApplicationInitializer的实现类之一是AbstractDispatcherServletInitializer,会创建spring容器、配置web.xml、注册过滤器。

    当存在多个WebApplicationContext会设置其层级关系。

编写代码测试

理论与实践相结合,利用tomcat + @HandlesTypes与ServletContainerInitializer + Spring-webmvc模拟SpringBoot去除web.xml启动。

代码地址:https://github.com/lmmarisej/light-springboot

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/180301.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!