• 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>
  • 相关阅读:
    SAM4E单片机之旅——2、LED闪烁之轮询定时器
    SAM4E单片机之旅——1、LED闪烁之空循环
    C#使用WinAPI 修改电源设置,临时禁止笔记本合上盖子时睡眠
    阻止系统自动睡眠的小软件,附C#制作过程
    Python3做采集
    判断浏览器类型
    任意几个数求和
    常见Z纯CSS小样式合集(三角形)
    数据脱敏项目中遇见的问题
    点击左侧跳到右侧
  • 原文地址:https://www.cnblogs.com/tdyang/p/12051325.html
Copyright © 2020-2023  润新知