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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM