SpringMVC注入原生Servlet组件与DispatcherServlet分析

如何在Spring MVC使用原生Servlet?

  • @ServletComponentScan(basePackages = “com.xxx.xxx”)
  • @WebServlet(urlPatterns = "/my/* ") 不经过Spring MVC的拦截器 需要注意的是跟SpringMVC不同,原生Filter 使用一个型号进行路径匹配 如 /my/*
  • @WebFilter(urlPatterns={"/css/*","/images/*"})
  • @WebListener
@ServletComponentScan(basePackages = {"com.corn.turorial.spring.servlet"})
@SpringBootApplication
public class SpringMain {
    public static void main(String[] args) {
        SpringApplication.run(SpringMain.class, args);
    }

}
@WebServlet(urlPatterns = {"/my/Servlet"})
public class MyCustomerServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType(MediaType.APPLICATION_JSON_VALUE);
        resp.getWriter().write("from my servlet!");
    }
}
@Slf4j
@WebFilter(urlPatterns = "/my/*")
public class MyCustomerFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("自定义filter 的 init方法");
    }

    @Override
    public void destroy() {
        log.info(" filter 销毁 ");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        log.info("进入 filter 内部");
        filterChain.doFilter(request, response);
    }
}

@Slf4j
@WebListener
public class MyCustomerListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info(" servlet 上下文 start");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info(" servlet 上下文 destroy");
    }
}

方式二使用RegistrationBean的方式注册原生Se rvlet组件

ServletRegistrationBean, FilterRegistrationBean, ServletListenerRegistrationBean

@Configuration
public class MyServletConfiguration {

    @Bean
    public ServletRegistrationBean<Servlet> myServlet() {
        ServletRegistrationBean bean = new ServletRegistrationBean();
        bean.setServlet(new MyCustomerServlet());
        bean.setUrlMappings(Arrays.asList("/my/Servlet"));
        return bean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.setFilter(new MyCustomerFilter());
        filter.setUrlPatterns(Arrays.asList("/my/*"));
        return filter;
    }

    @Bean
    public ServletListenerRegistrationBean myListener() {
        ServletListenerRegistrationBean<ServletContextListener> listener = new ServletListenerRegistrationBean<>();
        listener.setListener(new MyCustomerListener());
        return listener;
    }

}

DispatcherServlet的分析

Spring MVC的核心DispatcherServlet 的自动配置在 DispatcherServletAutoConfiguration类中

	@Configuration(proxyBeanMethods = false)
	@Conditional(DefaultDispatcherServletCondition.class)
	@ConditionalOnClass(ServletRegistration.class)
	@EnableConfigurationProperties(WebMvcProperties.class)
	protected static class DispatcherServletConfiguration {

		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
            // new了一个DispatcherServlet 
			DispatcherServlet dispatcherServlet = new DispatcherServlet();
			// 从webMvcProperties 中拿到各种配置设置属性
			return dispatcherServlet;
		}}
// .. 省略

进入DispatcherServlet内部查看细节 核心有一个onRefresh方法

protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}
// 各种初始化 如HandlerMapping HandlerAdpater
protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}

onRefresh被上层的FrameworkServlet调用

public void onApplicationEvent(ContextRefreshedEvent event) {
    this.refreshEventReceived = true;
    synchronized (this.onRefreshMonitor) {
        onRefresh(event.getApplicationContext());
    }
}

onApplicationEvent方法被FrameworkServlet 的内部类ContextRefreshListener调用而这个是实现了Spring的ApplicationListener接口 传入了ContextRefreshedEvent事件 在Spring启动过程中会触发这个事件,然后回调这个onRefresh方法从而初始化DispatcherServlet的各种属性

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        FrameworkServlet.this.onApplicationEvent(event);
    }
}

而DispatherServlet中的initStrategies 方法里面各种init方法如何实现

以initHandlerMappings 为例 BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false)使用这个方法获取容器中所有的HandlerMapping组件 但是我们从来没有注册过HandlerMapping组件. 这个组件的注册又得追溯到WebMvcConfigurationSupport这个类又是WebMVC自动配置的底层核心

private void initHandlerMappings(ApplicationContext context) {
   this.handlerMappings = null;

   if (this.detectAllHandlerMappings) {
      // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
      Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
      if (!matchingBeans.isEmpty()) {
         this.handlerMappings = new ArrayList<>(matchingBeans.values());
         // We keep HandlerMappings in sorted order.
         AnnotationAwareOrderComparator.sort(this.handlerMappings);
      }
   }
   // 省略

WebMvcConfigurationSupport默认注册了大量我们在MVC中会只用到的Bean

如RequestMappingHandlerMapping

image-20210208110316292

如RouterFunctionMapping

image-20210208110414516

如BeanNameUrlHandlerMapping

image-20210208110442322

如内容协商管理器image-20210208110351283

在WebMvcAutoConfiguration中 引入了EnableWebMvcConfiguration

image-20210208111108327

而 EnableWebMvcConfiguration 继承DelegatingWebMvcConfiguration DelegatingWebMvcConfiguration又继承了WebMvcConfigurationSupport 此时跟底层的Support联系了起来

需要注意的是如果标注了@EnableWebMVC注解 表示我们将全面接管 SpringMVC WebMvcAutoConfiguration所有的配置项将不在生效,只会提供最底层了WebMvcConfigurationSupport 的一些基本功能 开发不建议使用@EnableWebMVC注解 而是推荐标注@Configuration 继承WebMvcConfigurer 来覆盖我们需要拓展的逻辑

image-20210208111411623

image-20210208111424253

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值