Servlet3.0新特性之ServletContainerInitializer

0,注意

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

1,下載Servlet3.0 文檔

①,來到jcp官網:https://www.jcp.org/en/home/indexweb

②,搜索servlet,而後下載文檔spring

2,閱讀文檔

①,重點看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
指定的實現類,啓動並運行這個實現類的方法;傳入感興趣的類型;

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,覆寫其對應方法便可

相關文章
相關標籤/搜索