基于java文件的spring mvc配置
spring 3.2 引入了一个AbstractAnnotationConfigDispatcherServletInitializer实现了WebApplicationInitializer 接口,继承这个类可以替代web.xml的作用,spring也推荐使用基于java文件做spring配置。下面是spring 官网的一个配置
public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// GolfingAppConfig defines beans that would be in root-context.xml
return new Class[] { GolfingAppConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
// GolfingWebConfig defines beans that would be in golfing-servlet.xml
return new Class[] { GolfingWebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/golfing/*" };
}
}
一张spring文档中的图
image.pngweb容器在启动过程中如何找到WebApplicationInitializer
以tomcat为例子,tromcat在启动时会调用StandardContext.java的startInternal()方法,这个方法会去查找所有实现了 ServletContainerInitializer接口的类。SpringServletContainerInitializer实现了ServletContainerInitializer,SpringServletContainerInitializer又会去寻找实现了WebApplicationInitializer接口的类,这样就成功找到了。
贴上部分源码
StandardContext的startInternal()方法
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
initializers.entrySet()) {
try {
//调用SpringServletContainerInitializer的onStartup方法
entry.getKey().onStartup(entry.getValue(),
getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
SpringServletContainerInitializer 的onStartup 方法
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
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) {
// 调用实现了WebApplicationInitializer接口的onStartup方法
initializer.onStartup(servletContext);
}
}
Spring mvc 实现了WebApplicationInitializer接口的类
image.pngAbstractDispatcherServletInitializer的onStartup方法
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//ContextLoaderListener初始化,实例化IoC容器,并将此容器实例注册到ServletContext中;
super.onStartup(servletContext);
//DispatcherServlet初始化
registerDispatcherServlet(servletContext);
}
Root WebApplicationContext的初始化
上段代码中super.onStartup(servletContext)实现 Root WebApplicationContext的初始化
@Override
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
rootAppContext.register(configClasses);
return rootAppContext;
}
else {
return null;
}
}
AbstractContextLoaderInitializer的 registerContextLoaderListener 方法
protected void registerContextLoaderListener(ServletContext servletContext) {
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
//在web容器的servletcontext中添加ContextLoaderListener,监听web容器初始化
// web容器初始化时初始化Root WebApplicationContext,详见第一张图
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
Root WebApplicationContext 在tomcat 调用listenerStart方法 时初始化Root WebApplicationContext
关于Servlet WebApplicationContext的分析以后在做吧
参考
22. Web MVC framework
深入分析Spring 与 Spring MVC容器
Spring源码分析【3】-SpingWebInitializer的加载
tomcat实现ServletContext的addListener方法的源码解说(原创)
SpringMVC启动过程详解(li)
网友评论