栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springMVC零配置之上下文配置

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springMVC零配置之上下文配置

记得刚参加工作的时候,搭建springMVC框架还是需要手动配置web.xml文件,现在已经被渐渐淘汰了,在项目中几乎看不到有这种配置了,取而代之的是springMVC的零配置,原理就是tomcat的SPI的技术。

通过spi机制,tomcat会扫描所有jar下的
/META-INF/services/javax.servlet.ServletContainerInitializer文件。

在SpringServletContainerInitializer中通过@HandlesTypes注解,将实现了所有WebApplicationInitializer接口的类作为参数传入onstartup方法中。

然后遍历所有实现了WebApplicationInitializer接口的类,调用他们的onstartup方法。

接下来定义一个WebApplicationInitializer接口的类:

代码片段一:

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    //父容器
    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[]{SpringContainer.class};
    }

    //SpringMVC配置子容器
    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[]{MvcContainer.class};
    }

    //获取DispatcherServlet的映射信息
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

代码片段二:

//不扫描有@Controller注解的类
@ComponentScan(value = "com.dongsq",excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
})
public class SpringContainer {
}

代码片段三:

//扫描有@Controller注解的类
@ComponentScan(value = "com.dongsq",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
})
public class MvcContainer {
}

定义的类继承了AbstractAnnotationConfigDispatcherServletInitializer,而被继承类 又实现了WebApplicationInitializer接口。

所以由继承关系可知:会调用到AbstractDispatcherServletInitializer的onStartup方法。

看super.onStartup方法:

super.onStartup方法做了两件事:
一、创建spring上下文,createRootApplicationContext方法会调用复写的getRootConfigClasses方法,会将自定义的SpringConfainer类加入spring容器。

二、servlet容器注册监听。

AbstractDispatcherServletInitializer的onStartup方法中的super.onStartup方法调用完成,接下来会调用registerDispatcherServlet方法,创建mvc上下文,注册DispatcherServlet。

代码片段四:

protected void registerDispatcherServlet(ServletContext servletContext) {
	String servletName = getServletName();
	Assert.hasLength(servletName, "getServletName() must not return null or empty");

	//创建mvc的上下文,这里会调代码片段一中的getServletConfigClasses
	WebApplicationContext servletAppContext = createServletApplicationContext();
	Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");

	//创建DispatcherServlet对象,把springmvc上下文设置到DispatcherServlet中
	FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
	Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
	dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());

	//把DispatcherServlet放到servlet上下文中
	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);
	//钩子方法 会调用代码片段一中的getServletMappings方法
	registration.addMapping(getServletMappings());
	registration.setAsyncSupported(isAsyncSupported());

	//定义拦截器
	Filter[] filters = getServletFilters();
	if (!ObjectUtils.isEmpty(filters)) {
		for (Filter filter : filters) {
			registerServletFilter(servletContext, filter);
		}
	}

	customizeRegistration(registration);
}

接下来在servlet容器启动时,会调到监听类中的contextInitialized方法。

看initWebApplicationContext方法:

代码片段五:

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
	.....

	try {
		.....
		if (this.context instanceof ConfigurableWebApplicationContext) {
			ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
			if (!cwac.isActive()) {
				if (cwac.getParent() == null) {
					ApplicationContext parent = loadParentContext(servletContext);
					cwac.setParent(parent);
				}
				//这里会调用refresh方法,启动spring上下文
				configureAndRefreshWebApplicationContext(cwac, servletContext);
			}
		}
	//将spring上下文设置到servlet容器中
	servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
		.....
	}
	....
}

接下来servlet容器在启动的时候,会调到DispatcherServlet中的init方法,最终会调到initWebApplicationContext方法。
initWebApplicationContext方法代码:

protected WebApplicationContext initWebApplicationContext() {
	//从servlet下午文中获取spring的上下文对象
	WebApplicationContext rootContext =
			WebApplicationContextUtils.getWebApplicationContext(getServletContext());
	WebApplicationContext wac = null;

	if (this.webApplicationContext != null) {
		wac = this.webApplicationContext;
		if (wac instanceof ConfigurableWebApplicationContext) {
			ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
			if (!cwac.isActive()) {
				if (cwac.getParent() == null) {
					//设置spring上下文为springMVC的父上下文
					cwac.setParent(rootContext);
				}
				//在这启动springMVC上下文
				configureAndRefreshWebApplicationContext(cwac);
			}
		}
	}
	if (wac == null) {
		wac = findWebApplicationContext();
	}
	if (wac == null) {
		wac = createWebApplicationContext(rootContext);
	}

	if (!this.refreshEventReceived) {
		onRefresh(wac);
	}

	if (this.publishContext) {
		String attrName = getServletContextAttributeName();
		getServletContext().setAttribute(attrName, wac);
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
					"' as ServletContext attribute with name [" + attrName + "]");
		}
	}

	return wac;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/846863.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号