需要了解spring 3.0 的一些新特性
- 新特性
可插拔的Web框架,几乎所有基于Java的web框架都建立在servlet之上。现今大多数web框架要么通过servlet、要么通过Web.xml插入。利用标注(Annotation)来定义servlet、listener、filter将使之(可插拔)成为可能程序访问web.xml和动态改变web应用配置是所期望的特性。该JSR将致力于提供把不同web框架无缝地插入到web应用的能力。
- web-fragment.xml
http://jinnianshilongnian.iteye.com/blog/1750736
- 共享库 / 运行时可插拔性
在容器/应用启动时,由容器通过jar services API查找一个ServletContainerInitializer实例。框架提供的ServletContainerInitializer实现必须绑定在jar包的META-INF/services目录中的一个叫做javax.servlet.ServletContainerInitializer的文件中,根据每个jar services API,指定ServletContainerInitializer的实现类。
- @HandlesTypes(WebApplicationInitializer.class)
HandlesTypes注解作用:
在容器/应用启动时,由容器通过jar services API查找一个ServletContainerInitializer实例。框架提供的ServletContainerInitializer实现必须绑定在jar包的META-INF/services目录中的一个叫做javax.servlet.ServletContainerInitializer的文件,根据jar services API,指定ServletContainerInitializer的实现。除ServletContainerInitializer外,我们还有一个注解—HandlesTypes。在ServletContainerInitializer 实现上的HandlesTypes注解用于表示感兴趣的一些类,它们可能指定了HandlesTypes的value中的注解(类型、方法或自动级别的注解),或者是其类型的超类继承/实现了这些类之一。
容器使用HandlesTypes注解决定什么时候调用initializer的onStartup方法。当检测一个应用的类看是否它们匹配ServletContainerInitializer的HandlesTypes指定的条件时,
如果应用的一个或多个可选的JAR包缺失,容器可能遇到类装载问题。由于容器不能决定是否这些类型的类装载失败将阻止应用正常工作,它必须忽略它们,同时也提供一个将记录它们的配置选项。
- SpringServletContainerInitializer
org/springframework/spring-web/4.3.12.RELEASE/spring-web-4.3.12.RELEASE.jar!/META-INF/services/javax.servlet.ServletContainerInitializer
@HandlesTypes(WebApplicationInitializer.class)//感兴趣的类
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
//WebApplicationInitializer 所有的子类集合
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
//只把自定义的配置类继承自 AbstractAnnotationConfigDispatcherServletInitializer 添加到集合中去
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);//WebApplicationInitializer.onStartup() 开始spring 框架的加载
}
}
}
http://blog.csdn.net/wangyangzhizhou/article/details/52013779
- AbstractDispatcherServletInitializer.java
关键类:
AbstractDispatcherServletInitializer.java
//关键方法
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//首先注册根容器
super.onStartup(servletContext);
//注册 spring mvc 的 DispatcherServlet
registerDispatcherServlet(servletContext);
}
super.onStartup(servletContext);父类的启动方法做了什么
- AbstractContextLoaderInitializer.java
@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");
}
}
- 到此以上的过程都是为了spring 容器启动做的一些配置(可以理解为替代wem.xml 的所使用的 java config)
//ContextLoaderListener 监听器上场
监听器:
EventListener.java
https://www.cnblogs.com/atyou/archive/2013/01/07/2850321.html 使用,serlvet使用的这种机制来实现事件触发对listener的通知
ServletContextListener.java
这个接口接收事件通知,关于ServletContext 生命周期的变化,servlet filter 等监听
ContextLoaderListener.java
spring mvc Bootstrap listener to start up and shut down Spring's root
//启动类监听到serlvet上下文启动然后开始初始化上spring下文
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
//Initialize the root web application context.
@Override
public void contextInitialized(ServletContextEvent event) {
//初始化spring容器
initWebApplicationContext(event.getServletContext());
}
// Close the root web application context.
@Override
public void contextDestroyed(ServletContextEvent event) {
//销毁spring容器 ( 就是当DispatcherServlet销毁的时候 )
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
至此就开始初始化spring 父(根)容器和spring mvc 子容器