spring 源碼筆記 spring-web如何實現servlet規範

servlet 3.0 規範

角色:應用方(spring) + servlet + web容器(tomcat)

servlet 3.0 規範
  • 規範提供ServletContainerInitializer接口,應用方提供實現類。
  • 規範提供"根目錄/resources/META-INF/services/javax.servlet.ServletContainerInitializer"路徑,應用方把ServletContainerInitializer接口實現類全類名寫在該文件內。
  • 規範提供@HandlesTypes註解,由應用方配置,web容器解析,解析得到的實現類集合將通過參數傳給ServletContainerInitializer.onStartup方法。
  • web容器啓動完成回調ServletContainerInitializer.onStartup方法。

spring-web 如何實現servlet規範

spring提供WebApplicationInitializer接口,讓程序員方便地進行web容器初始化回調。
spring把WebApplicationInitializer接口配置到@HandlesTypes,讓web容器找到所有WebApplicationInitializer接口的實現類。
spring提供SpringServletContainerInitializer類實現ServletContainerInitializer接口,把web容器找到的實現類實例化出來,並執行。
spring把SpringServletContainerInitializer全類名配置到servlet規定的文件內,由web容器調用。

WebApplicationInitializer
public interface WebApplicationInitializer {
	void onStartup(ServletContext servletContext) throws ServletException;
}
SpringServletContainerInitializer
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
	// webAppInitializerClasses:web容器找到的WebApplicationInitializer的實現類集合
	@Override
	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
		// 執行集合
		List<WebApplicationInitializer> initializers = new LinkedList<>();
		if (webAppInitializerClasses != null) {
			for (Class<?> waiClass : webAppInitializerClasses) {
				// 驗證 添加到執行集合
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						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);
		for (WebApplicationInitializer initializer : initializers) {
			// 遍歷執行
			initializer.onStartup(servletContext);
		}
	}
}
/resources/META-INF/services/javax.servlet.ServletContainerInitializer
org.springframework.web.SpringServletContainerInitializer

自己實現servlet 3.0 規範

CustomWebApplicationInitializer
// 參考spring的WebApplicationInitializer接口
public interface CustomWebApplicationInitializer {
    void onStartup(ServletContext servletContext) throws ServletException;
}
CustomServletContainerInitializer
// 提供ServletContainerInitializer接口實現類,加上@HandlesTypes註解,傳入自己提供的CustomWebApplicationInitializer接口
@HandlesTypes(CustomWebApplicationInitializer.class)
public class CustomServletContainerInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        List<CustomWebApplicationInitializer> initializers = new LinkedList<>();
        if (c != null) {
            for (Class<?> waiClass : c) {
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && CustomWebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                    try {
                        initializers.add((CustomWebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance());
                    } catch (Throwable ex) {
                        throw new ServletException("Failed to instantiate CustomWebApplicationInitializer class", ex);
                    }
                }
            }
        }
        if (initializers.isEmpty()) {
            ctx.log("No Spring CustomWebApplicationInitializer types detected on classpath");
            return;
        }
        ctx.log(initializers.size() + " Spring CustomWebApplicationInitializers detected on classpath");
        AnnotationAwareOrderComparator.sort(initializers);
        for (CustomWebApplicationInitializer initializer : initializers) {
            initializer.onStartup(ctx);
        }
    }
}
/resources/META-INF/services/javax.servlet.ServletContainerInitializer
com.tbryant.springmvctest.customspringmvc.core.CustomServletContainerInitializer

使用自己實現servlet 3.0 規範

MyCustomWebApplicationInitializer
public class MyCustomWebApplicationInitializer implements CustomWebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) {
        System.out.println("web容器初始化回調,可在此添加spring容器啓動代碼");
    }
}

其他類文件請參考spring 零xml配置 & 內置tomcat 啓動spring mvc

執行結果

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章