①,要想使用servlet3.0,必须使用tomcat7.0及以上版本java
①,来到jcp官网:https://www.jcp.org/en/home/indexweb
②,搜索servlet,而后下载文档spring
①,重点看8.2.4 Shared libraries / runtimes pluggability 章节tomcat
②,重点是这一段mvc
③,翻译以下app
一、Servlet容器启动会扫描,当前应用里面每个jar包的
ServletContainerInitializer的实现
二、提供ServletContainerInitializer的实现类;
必须绑定在,META-INF/services/javax.servlet.ServletContainerInitializer
文件的内容就是ServletContainerInitializer实现类的全类名;ide
④,下面这一段也很关键spa
⑤,大意是咱们能够给ServletContainerInitializer 的实现类添加 @HandlesTypes 注解翻译
⑥,在其onStartup 方法上即可以获得咱们感兴趣的类debug
⑦,总结
总结:容器在启动应用的时候,会扫描当前应用每个jar包里面
META-INF/services/javax.servlet.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); } } }
①,继承关系以下
②,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(); }
因此咱们在用配置类建立springmvc应用时,只需继承AbstractAnnotationConfigDispatcherServletInitializer,覆写其对应方法便可