美文网首页
## Spring MVC 注解方式使用及和Tomcat,Ser

## Spring MVC 注解方式使用及和Tomcat,Ser

作者: 码而优则仕 | 来源:发表于2020-07-28 08:55 被阅读0次

    Spring MVC 注解方式使用及和Tomcat,Servlet的整合

    ServletContainerInitializer该类是Servlet 提供的接口,该接口的实现类会被Tomcat 等 Web容器,在启动的时候会使用 JAR 服务API---service-api 来发现 ,并调用实现类里面的 onStartup 方法

    public interface ServletContainerInitializer {
        void onStartup(Set<Class<?>> var1, ServletContext var2) throws ServletException;
    }
    

    Spring MVC 就是通过实现了 ServletContainerInitializer 接口 的SpringServletContainerInitializer 中的 onStartup 方法来完成Spring的容器以及相关的 MVC 相关配置的加载。

    如下:

    但是在该类的 onStartup 方法中并没有看到显示的初始化 Servlet 的地方,只是for循环调用 WebApplicationInitializer 接口的实现类的方法 onStartup;所以 初始化 Servlet 就是在这些实现类的 onStartup中完成的,WebApplicationInitializer的相关实现类是 @HandlesTypes 注解标签注入的,类似 Spring 中的@Autowired 注解, 会自动找到 标签里面属性的Class 的实现类,并注入到 Tomcat 容器里面(HandlesTypes注解是Servlet里面的注解)

    @HandlesTypes(WebApplicationInitializer.class)
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        @Override
        public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
                throws ServletException {
    
            List<WebApplicationInitializer> initializers = new LinkedList<>();
    
            if (webAppInitializerClasses != null) {
                for (Class<?> waiClass : webAppInitializerClasses) {
                    // Be defensive: Some servlet containers provide us with invalid classes,
                    // no matter what @HandlesTypes says...
                    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                            WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                        try {
                            initializers.add((WebApplicationInitializer)
                                    ReflectionUtils.accessibleConstructor(waiClass).newInstance());
                        }
                        catch (Throwable ex) {
                            throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                        }
                    }
                }
            }
    
            if (initializers.isEmpty()) {
                servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
                return;
            }
    
            servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
            AnnotationAwareOrderComparator.sort(initializers);
            for (WebApplicationInitializer initializer : initializers) {
                initializer.onStartup(servletContext);
            }
        }
    
    }
    
    public interface WebApplicationInitializer {
       void onStartup(ServletContext servletContext) throws ServletException;
    
    }
    
    public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer {
    
    public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
    

    支持注解方式的 DispatcherServlet,可以继承 AbstractAnnotationConfigDispatcherServletInitializer 抽象类来实现我们的业务需求

    如下所示:

    package com.yuns.config;
    
    import org.springframework.web.filter.CharacterEncodingFilter;
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    
    import javax.servlet.Filter;
    
    /**
     * 实现 无 web.xml 化 的全注解的 Spring MVC 配置
     */
    public class StartWebApplicationContextInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
       /**
        * SpringContext 中相关的类-- 根容器的配置类
        *
        * @return
        */
       @Override
       protected Class<?>[] getRootConfigClasses() {
          return new Class<?>[]{SpringRootConfig.class};
       }
    
       /**
        * DispatcherServlet 中上下文相关的类--子容器的配置类
        *
        * @return
        */
       @Override
       protected Class<?>[] getServletConfigClasses() {
          return new Class<?>[]{MVCConfig.class};
       }
    
       /**
        * Servlet 请求映射路径
        *
        * @return
        */
       @Override
       protected String[] getServletMappings() {
          //所有请求都会经过 DispatcherServlet 来处理
          return new String[]{"/"};
       }
    
       /**
        * 拦截并处理请求的编码
        *
        * @return
        */
       @Override
       protected Filter[] getServletFilters() {
          CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
          //设置拦截请求后的统一编码
          encodingFilter.setEncoding("UTF-8");
          //强制编码属性设置为 true--对请求进行强制的 UTF-8 编码
          encodingFilter.setForceEncoding(true);
          return new Filter[]{encodingFilter};
       }
    }
    
    package com.yuns.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * 扫描除了Controller以外的基础服务层
     *
     * @author wsq
     * @version SpringRootConfig.java  2020/7/26  上午9:59 下午
     */
    @ComponentScan("com.yuns.service")
    //让其作为配置Bean 注册到 root 容器中
    @Configuration
    public class SpringRootConfig {
    }
    
    package com.yuns.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.view.InternalResourceViewResolver;
    
    /**
     * 扫描 Spring MVC 相关的 Bean
     *
     * @author wsq
     * @version MVCConfig.java  2020/7/26  上午9:59 下午
     */
    @ComponentScan("com.yuns.controller")
    //让其作为配置Bean 注册到 root 容器中
    @Configuration
    //开启容器的 MVC 功能
    @EnableWebMvc
    public class MVCConfig {
    
       /**
        * 内部资源视图解析器实例
        * 创建并返回视图解析器实例
        *
        * @return
        */
       //方法上加这个注解标签之后,Spring 容器在启动并读入 MVCConfig 本类的时候,
       //调用 viewResolver 这个方法,将方法的返回值作为 Bean 注入到容器中
       @Bean
       public InternalResourceViewResolver viewResolver() {
          InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
          //解析的路径前缀和后缀进行赋值
          //让视图解析器解析 Controller 指定的 View路径 的时候,自动给路径加上设置好的前缀和后缀
          internalResourceViewResolver.setPrefix("/WEB-INF/jsp/");
          internalResourceViewResolver.setSuffix(".jsp");
          return internalResourceViewResolver;
       }
    }
    

    以上完成IOC 容器的创建和DispatcherServlet实例,以上是基于注解的 IOC 容器初始化,而Web.xml的初始化则是通过下面的 ContextLoaderListener Servlet 的监听器 完成的;

    注意:注解的初始化先于 web.xml方式的初始化。

    注意:不管是基于注解方式还是web.xml方式,触发机制都是Tomcat容器启动的时候触发的,即SpringServletContainerInitializer 中的 onStartup 方法 或 ContextLoaderListener 的 contextInitialized 方法都是 tomcat 触发的,即 tomcat 应用本身自己维护的线程池中的线程触发的。

    Root IOC 容器是什么时候刷新的???—包含非 Spring MVC Bean

    ContextLoaderListener 实现了 ServletContextListener 本质上 是 一个Servlet 的监听器,Tomcat 会优先加载 Servlet 的监听器组件,以保证 在 Servlet被创建之前即 Context 实例进行初始化的时候,去调用 ServletContextListener 接口定义的contextInitialized 方法 来根据 contextConfigLocation指定的位置 去读取并解析 Spring 容器的配置,创建出容器的实例并对容器进行刷新操作,在刷新之后对 Controller和请求的映射关系进行创建。不管是web.xml的方式还是注解的方式都会走到这一步:调用 ServletContextListener 接口定义的contextInitialized 方法

    MVC Bean 的加载???

    在 DispatcherServlet 的初始化的时候完成的

    三种类型的 HandlerMapping:

    RequestMappingHandlerMapping:处理 @RequestMapping 注解标签的

    AbstractHandlerMethodMapping.

    BeanNameUrlHandlerMapping

    RouterFunctionMapping

    相关文章

      网友评论

          本文标题:## Spring MVC 注解方式使用及和Tomcat,Ser

          本文链接:https://www.haomeiwen.com/subject/bcbxrktx.html