Servlet3.0新特性之ServletContainerInitializer

0,注意

①,要想使用servlet3.0,必须使用tomcat7.0及以上版本

1,下载Servlet3.0 文档

①,来到jcp官网:https://www.jcp.org/en/home/index

②,搜索servlet,然后下载文档

2,阅读文档

①,重点看8.2.4 Shared libraries / runtimes pluggability 章节

②,重点是这一段

③,翻译如下

1、Servlet容器启动会扫描,当前应用里面每一个jar包的
    ServletContainerInitializer的实现
2、提供ServletContainerInitializer的实现类;
    必须绑定在,META-INF/services/javax.servlet.ServletContainerInitializer
    文件的内容就是ServletContainerInitializer实现类的全类名;

④,下面这一段也很关键

⑤,大意是我们可以给ServletContainerInitializer 的实现类添加 @HandlesTypes 注解

⑥,在其onStartup 方法上便可以得到我们感兴趣的类

⑦,总结

总结:容器在启动应用的时候,会扫描当前应用每一个jar包里面
META-INF/services/javax.servlet.ServletContainerInitializer
指定的实现类,启动并运行这个实现类的方法;传入感兴趣的类型;

3,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);
		}
	}
}

4,WebApplicationInitializer 相关类详解

①,继承关系如下

②,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();

}

②,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();
}

③,AbstractAnnotationConfigDispatcherServletInitializer

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

5,总结

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

猜你喜欢

转载自my.oschina.net/u/3574106/blog/1819394