您的位置:首页 > 编程语言 > Java开发

使用java config 配置的spring mvc 启动过程分析

2018-01-13 19:00 561 查看

需要了解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 子容器
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring mvc java servlet