zoukankan      html  css  js  c++  java
  • servlet中ServletContainerInitializer

    根据官方文档到的说明

    public interface ServletContainerInitializer
    Interface which allows a library/runtime to be notified of a web application's startup phase and perform any required programmatic 
    registration of servlets, filters, and listeners in response to it. Implementations of this interface may be annotated with HandlesTypes, in order to receive (at their onStartup(java.util.Set>,
    javax.servlet.ServletContext) method) the Set of application classes that implement, extend, or have been annotated with the class types specified by the annotation. If an implementation of this interface does not use this annotation, or none of the application classes match the ones specified
    by the annotation, the container must pass a null Set of classes to onStartup(java.util.Set>, javax.servlet.ServletContext). When examining the classes of an application to see if they match any of the criteria specified by the HandlesTypes annotation
    of a ServletContainerInitializer, the container may run into classloading problems if any of the application's optional JAR files
    are missing. Because the container is not in a position to decide whether these types of classloading failures will prevent the
    application from working correctly, it must ignore them, while at the same time providing a configuration option that would log them. Implementations of this interface must be declared by a JAR file resource located inside the META-INF/services directory
    and named for the fully qualified class name of this interface, and will be discovered using the runtime's service provider lookup
    mechanism or a container specific mechanism that is semantically equivalent to it. In either case, ServletContainerInitializer
    services from web fragment JAR files excluded from an absolute ordering must be ignored, and the order in which these services
    are discovered must follow the application's classloading delegation model.

    在容器启动的时候,他会去加载META-INF/services/javax.servlet.ServletContainerInitializer文件下指定的实现类

    demo:

    创建文件

     

     里面的内容是实现了javax.servlet.ServletContainerInitializer的自定义类,并重写它的方法

    @HandlesTypes(value = {HelloService.class})
    public class MyServletContainerInitializer implements ServletContainerInitializer {
        @Override
        public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
                for(Class clazz : set){
                    System.out.println("获取的class..."+clazz);
                }
        }
    }
    @HandlesTypes 可以获取到指定类型的所有子
    Set<Class<?>> set获取到的class
    servletContext servlet上下文

    创建HelloService一个子类型:

    启动程序,看打印结果:
    获取的class...class com.servlet.HelloServiceImp
    获取的class...class com.servlet.AbstractHelloService
    在加载的时候,onStartup()方法执行时,我们也可以加入自定义的servlet,filter,listener
            servletContext.addServlet("userServlet",UserServlet.class).addMapping("/user");
    
                servletContext.addListener(Mylistener.class);
    
                servletContext.addFilter("userFilter",userFilter.class).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),true,"/*");

    在springmvc中,web容器启动到的时候也会去加载META-INF/services/javax.servlet.ServletContainerInitializer,加载指定的类

    SpringServletContainerInitializer

    来看看SpringServletContainerInitializer这个类

    @HandlesTypes(WebApplicationInitializer.class)
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        @Override
        public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
                throws ServletException {
    
            List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
    
            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) 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);
            }
        }
    
    }
    @HandlesTypes(WebApplicationInitializer.class)这和servlet中的操作一样,他会去获取到WebApplicationInitializer的子类型

    WebApplicationInitializer下三个抽象类:
    AbstractContextLoaderInitializer:创建根容器createRootApplicationContext()
    @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            registerContextLoaderListener(servletContext);
        }
        protected void registerContextLoaderListener(ServletContext servletContext) {
            WebApplicationContext rootAppContext = createRootApplicationContext();
            if (rootAppContext != null) {
                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");
            }
        }
    AbstractDispatcherServletInitializer:
      1、创建web的ioc容器createServletApplicationContext()
      2、创建DispatcherServlet:createDispatcherServlet(servletAppContext)
        添加到ServletContext中:servletContext.addServlet(servletName, dispatcherServlet)
    @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            super.onStartup(servletContext);
            registerDispatcherServlet(servletContext);
        }
    
        protected void registerDispatcherServlet(ServletContext servletContext) {
            String servletName = getServletName();
            Assert.hasLength(servletName, "getServletName() must not return empty or null");
    
            WebApplicationContext servletAppContext = createServletApplicationContext();
            Assert.notNull(servletAppContext,
                    "createServletApplicationContext() did not return an application " +
                    "context for servlet [" + servletName + "]");
    
            FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
            dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
    
            ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
            Assert.notNull(registration,
                    "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);
        }
    AbstractAnnotationConfigDispatcherServletInitializer:

        创建根容器:createRootApplicationContext(),它覆写了上面的方法,获取RootConfigClasses类的配置
        创建web的ioc容器:createServletApplicationContext() ,它覆写了上面的方法,获取ServletConfigClasses类的配置
    @Override
        protected WebApplicationContext createRootApplicationContext() {
            Class<?>[] configClasses = getRootConfigClasses();
            if (!ObjectUtils.isEmpty(configClasses)) {
                AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
                rootAppContext.register(configClasses);
                return rootAppContext;
            }
            else {
                return null;
            }
        }
        @Override
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext();
            Class<?>[] configClasses = getServletConfigClasses();
            if (!ObjectUtils.isEmpty(configClasses)) {
                servletAppContext.register(configClasses);
            }
            return servletAppContext;
        }
    写一个类MyWebAppInitializer来继承AbstractAnnotationConfigDispatcherServletInitializer
    public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class<?>[] { RootConfig.class };
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class<?>[] { App1Config.class };
        }
    
        @Override
        protected String[] getServletMappings() {
            return new String[] { "/app1/*" };
        }
    }

    写配置类RootConfig:它不去扫描controller,controller交给App1Config扫描

    @ComponentScan(value = "com.springmvc",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})})
    public class RootConfig {
    }

    写配置类App1Config:

    @ComponentScan(value = "com.springmvc",includeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,classes = {Controller.class})})
    public class App1Config {
    }
    这是使用注解来实现配置,用web.xml文件来配置:
    <web-app>
    
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/root-context.xml</param-value>
        </context-param>
    
        <servlet>
            <servlet-name>app1</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/app1-context.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>app1</servlet-name>
            <url-pattern>/app1/*</url-pattern>
        </servlet-mapping>
    
    </web-app>
  • 相关阅读:
    [置顶] Guava学习之Lists
    Study notes for B-tree and R-tree
    uva 620 Cellular Structure
    [置顶] 程序员面试之道(《程序员面试笔试宝典》)之看着别人手拿大把的offer,不淡定了怎么办?
    HDU 4046 Panda (ACM ICPC 2011北京赛区网络赛)
    有N个正实数(注意是实数,大小升序排列) x1 , x2 ... xN,另有一个实数M。 需要选出若干个x,使这几个x的和与 M 最接近。 请描述实现算法,并指出算法复杂度
    C# 未能加载文件或程序集“MySQLDriverCS..." 错误解决
    LA 3942 Remember the Word(前缀树&树上DP)
    原根-快速求解一个数的原根
    线程初步了解
  • 原文地址:https://www.cnblogs.com/tdyang/p/12051325.html
Copyright © 2011-2022 走看看