美文网首页
## 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