listener filter servlet_Spring(二十二)Spring MVC 对Tomcat 的 Servlet,Filter和Listener 组装分析...

博主从Spring Boot 去看Spring MVC 启动过程,而Spring Boot 默认集成了内置的tomcat容器,所以分析Spring MVC ,中间还夹着挺多Tomcat逻辑。

Java web中有三大组件:

  1. Servlet

  2. Filter

  3. Listener

记得开始学习 JavaWeb时候,就是通过这几个入门的,定义 Servlet用于处理Http请求,定义 Filter来对请求进行拦截,而使用 ServletContextListener 来监听容器创建和销毁动作。

本文主要基于Tomcat来分析。

在Spring Boot 中,如果要定义这三种组件,可以这样进行:

  1. 使用 @ServletComponentScan("com.anla.springwebmvc.servlet") 开启对自定义Servlet包扫描

  2. 对三种组件,相应使用 @WebServlet、 @WebFilter、 @WebListener 进行配置,而后实现相应javax提供接口( HttpServlet、 Filter、 ServletContextListener)。例如加上一个自定义Servlet写法:

@WebServlet(urlPatterns = "/myservlelt")

public class MyServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

response.setCharacterEncoding("UTF-8");

response.setHeader("Content-type","text/html;charset=utf-8");

response.getWriter().println("my springboot servlet……测试在Spring Boot自定义Servlet");

response.getWriter().flush();

response.getWriter().close();

}

@Override

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request,response);

}

}

ServletComponentScan

使用了 ServletComponentScan 注解,然后我们当然会看这个扫描做了什么事。

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Import(ServletComponentScanRegistrar.class)

public @interface ServletComponentScan {

而在 ServletComponentScanRegistrar 中,通过 registerBeanDefinitions 注册了一个bean ServletComponentRegisteringPostProcessor

@Override

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);

if (registry.containsBeanDefinition(BEAN_NAME)) {

updatePostProcessor(registry, packagesToScan);

}

else {

addPostProcessor(registry, packagesToScan);

}

}

BEAN_NAME 为:servletComponentRegisteringPostProcessor

再看看 ServletComponentRegisteringPostProcessor :

class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {

它是一个 BeanFactoryPostProcessor,所以应该是Spring 扫描完Configuration 类后,直接就会轮到 它,看看重写的方法:

@Override

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

// 只有是内置服务器,才会执行

if (isRunningInEmbeddedWebServer()) {

// 构造扫描器,过滤WebServlet,WebFilter,WebListener 三种

ClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider();

for (String packageToScan : this.packagesToScan) {

// 具体扫描动作

scanPackage(componentProvider, packageToScan);

}

}

}

判断扫描规则,而后调用 scanPackage 对注解上传入的报名进行依次扫描:

private void scanPackage(ClassPathScanningCandidateComponentProvider componentProvider, String packageToScan) {

for (BeanDefinition candidate : componentProvider.findCandidateComponents(packageToScan)) {

if (candidate instanceof ScannedGenericBeanDefinition) {

for (ServletComponentHandler handler : HANDLERS) {

// 依次判断类型

handler.handle(((ScannedGenericBeanDefinition) candidate),

(BeanDefinitionRegistry) this.applicationContext);

}

}

}

}

  1. 对 componentProvider.findCandidateComponents(packageToScan) 扫描到的所有信息进行过滤。

  2. HANDLERS 中存储着三种类型handler WebServletHandler、 WebFilterHandler、 WebListenerHandler,分别用于解析三种类型组件。如果发现是对应类型Bean,则将其作为相应bean注册进容器。分别看这三个 Handler的 doHandle方法:WebFilterHandler

@Override

public void doHandle(Map<String, Object> attributes, ScannedGenericBeanDefinition beanDefinition,

BeanDefinitionRegistry registry) {

BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterRegistrationBean.class);

builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));

builder.addPropertyValue("dispatcherTypes", extractDispatcherTypes(attributes));

builder.addPropertyValue("filter", beanDefinition);

builder.addPropertyValue("initParameters", extractInitParameters(attributes));

String name = determineName(attributes, beanDefinition);

builder.addPropertyValue("name", name);

builder.addPropertyValue("servletNames", attributes.get("servletNames"));

builder.addPropertyValue("urlPatterns", extractUrlPatterns(attributes));

registry.registerBeanDefinition(name, builder.getBeanDefinition());

}

WebListenerHandler

@Override

protected void doHandle(Map<String, Object> attributes, ScannedGenericBeanDefinition beanDefinition,

BeanDefinitionRegistry registry) {

BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServletListenerRegistrationBean.class);

builder.addPropertyValue("listener", beanDefinition);

registry.registerBeanDefinition(beanDefinition.getBeanClassName(), builder.getBeanDefinition());

}

WebServletHandler

@Override

public void doHandle(Map<String, Object> attributes, ScannedGenericBeanDefinition beanDefinition,

BeanDefinitionRegistry registry) {

BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServletRegistrationBean.class);

builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));

builder.addPropertyValue("initParameters", extractInitParameters(attributes));

builder.addPropertyValue("loadOnStartup", attributes.get("loadOnStartup"));

String name = determineName(attributes, beanDefinition);

builder.addPropertyValue("name", name);

builder.addPropertyValue("servlet", beanDefinition);

builder.addPropertyValue("urlMappings", extractUrlPatterns(attributes));

builder.addPropertyValue("multipartConfig", determineMultipartConfig(beanDefinition));

registry.registerBeanDefinition(name, builder.getBeanDefinition());

}

即通过注解中传入的参数,分别传入到 BeanDefinition中,对应三种bean分别为: ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean8067bddf9edc36274dd672291bd77555.png到目前为止,Spring 对 ServletFilterListener 组装已经结束,就是将他们按照特定类型放入到Spring 容器中。

下篇文章,将看看Spring 何时使用他们,敬请期待。

觉得博主写的有用,不妨关注博主公众号: 六点A君。哈哈哈,一起研究Spring:e051339d888cddfe675ac2ae6f8374ff.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值