• (三)Web模块:【5】Servlet3.0 与 SpringMVC 整合


    一、SpringMVC对ServletContainerInitializer 类的实现

      配置信息:

      查看SpringServletContainerInitializer

    //感兴趣的类为WebApplicationInitializer
    @HandlesTypes(WebApplicationInitializer.class)
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        //webAppInitializerClasses:所有WebApplicationInitializer 类型的Class
        @Override
        public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
                throws ServletException {
    
            List<WebApplicationInitializer> initializers = new LinkedList<>();
    
            if (webAppInitializerClasses != null) {
                for (Class<?> waiClass : webAppInitializerClasses) {
                    // 如果该Class 不是接口,不是抽象类,并且是WebApplicationInitializer类型的类
                    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                            WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                        try {
                            //实例化该类,并加入到initializers集合中
                            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);
            //遍历initializers集合中的类
            for (WebApplicationInitializer initializer : initializers) {
                //调用其onStartup方法
                initializer.onStartup(servletContext);
            }
        }
    }

    二、WebApplicationInitializer 相关类详解

      1、继承关系如下

      

      2、AbstractContextLoaderInitializer

    public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer {
    
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            //注册容器监听
            registerContextLoaderListener(servletContext);
        }
    
        protected void registerContextLoaderListener(ServletContext servletContext) {
            //创建根容器
            WebApplicationContext rootAppContext = createRootApplicationContext();
            if (rootAppContext != null) {
                //根据根容器,创建容器监听,相当于以前在xml文件里配置ContextLoaderListener
                ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
                listener.setContextInitializers(getRootApplicationContextInitializers());
                servletContext.addListener(listener);
            }
            else {
                logger.debug("No ContextLoaderListener registered, as " +
                        "createRootApplicationContext() did not return an application context");
            }
        }
       //创建根容器方法是个抽象方法,留给子类实现
       protected abstract WebApplicationContext createRootApplicationContext();
    
    }

      3、AbstractDispatcherServletInitializer

        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            super.onStartup(servletContext);
            //注册一个DispatcherServlet
            registerDispatcherServlet(servletContext);
        }
        protected void registerDispatcherServlet(ServletContext servletContext) {
            String servletName = getServletName();
            Assert.hasLength(servletName, "getServletName() must not return null or empty");
            //创建一个servlet容器
            WebApplicationContext servletAppContext = createServletApplicationContext();
            Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");
            //创建一个dispatcherServlet 
            FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
            Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
            dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
            //给servlet容器 添加dispatcherServlet 得到一个注册器
            ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
            if (registration == null) {
                throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
                        "Check if there is another servlet registered under the same name.");
            }
            //在容器启动时就加载
            registration.setLoadOnStartup(1);
            //添加拦截路径
            registration.addMapping(getServletMappings());
            registration.setAsyncSupported(isAsyncSupported());
    
            Filter[] filters = getServletFilters();
            if (!ObjectUtils.isEmpty(filters)) {
                for (Filter filter : filters) {
                    registerServletFilter(servletContext, filter);
                }
            }
    
            customizeRegistration(registration);
        }
        // 这是一个抽象方法,留给子类实现的
        protected abstract String[] getServletMappings();
    }

      4、AbstractAnnotationConfigDispatcherServletInitializer

    public abstract class AbstractAnnotationConfigDispatcherServletInitializer
            extends AbstractDispatcherServletInitializer {
         //覆盖了AbstractContextLoaderInitializer的createRootApplicationContext方法,
         //用于创建根容器
         @Override
         protected WebApplicationContext createRootApplicationContext() {
            //得到根容器的Class
            Class<?>[] configClasses = getRootConfigClasses();
            if (!ObjectUtils.isEmpty(configClasses)) {
                //创建一个web容器
                AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
                //注册配置类
                context.register(configClasses);
                return context;
            }
            else {
                return null;
            }
        }
        
        @Override
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext();
            Class<?>[] configClasses = getServletConfigClasses();
            if (!ObjectUtils.isEmpty(configClasses)) {
                servletAppContext.register(configClasses);
            }
            return servletAppContext;
        }
        
       //得到根容器配置类,这是一个抽象方法,留给子类实现,覆盖了AbstractContextLoaderInitializer
       protected abstract Class<?>[] getRootConfigClasses();
       //得到Servlet容器配置类,覆盖了AbstractDispatcherServletInitializer 的方法
       protected abstract Class<?>[] getServletConfigClasses();
    }

      所以我们在用配置类创建springmvc应用时,只需继承AbstractAnnotationConfigDispatcherServletInitializer,覆写其对应方法即可

    三、Servlet3.0 整合 SpringMVC

      1、创建父容器配置类

    //Spring的容器不扫描controller;父容器
    @ComponentScan(value="com.njf", excludeFilters={
            @ComponentScan.Filter(type= FilterType.ANNOTATION,classes={Controller.class})
    })
    public class RootConfig {}

      2、创建子容器配置类

    //SpringMVC只扫描Controller;子容器
    //useDefaultFilters=false 禁用默认的过滤规则;
    @ComponentScan(value="com.njf", includeFilters={
            @ComponentScan.Filter(type = FilterType.ANNOTATION, classes={Controller.class})
    }, useDefaultFilters=false)
    public class AppConfig {}

      3、自定义初始化器,并指定配置类

    //web容器启动的时候创建对象;调用方法来初始化容器以前前端控制器
    public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        //获取根容器的配置类;(Spring的配置文件)   父容器;
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class<?>[]{RootConfig.class};
        }
    
    
        //获取web容器的配置类(SpringMVC配置文件)  子容器;
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class<?>[]{AppConfig.class};
        }
    
    
        //获取DispatcherServlet的映射信息
        //  /:拦截所有请求(包括静态资源(xx.js,xx.png)),但是不包括*.jsp;
        //  /*:拦截所有请求;连*.jsp页面都拦截;jsp页面是tomcat的jsp引擎解析的;
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
    
    }

      4、创建一个 Controller

    @Controller
    public class HelloController {
    
        @Autowired
        HelloService helloService;
    
        @ResponseBody
        @RequestMapping(value = "/hello", method = RequestMethod.GET)
        public String hello() {
            String result = helloService.sayHello("Tomcat...");
            return result;
        }
    }

      5、创建一个 Service

    @Service
    public class HelloService {
    
        public String sayHello(String word) {
            System.out.println("Hello," + word);
            return "Hello" + word;
        }
    }

      6、测试正常运行。

  • 相关阅读:
    2013.11.19上班 任务:写文档
    js 时间比较和货币格式显示
    SQL优化
    多线程消费队列中的接口数据,接口数据来源是kafka
    List<Map<String, Object>> 中根据某一个属性进行排序
    ES查询操作
    Valid Sudoku
    Decode Ways
    Jump Game
    Best Time to Buy and Sell Stock II
  • 原文地址:https://www.cnblogs.com/niujifei/p/15593195.html
Copyright © 2020-2023  润新知