最近在springmvc传值问题遇到麻烦,特意了解一下springmvc的源码;
首先带着几个问题:
1.springmvc是个什么东西?
2.springmvc启动的时候做了什么?
3.springmvc怎么做的请求处理?
4.controller的方法中,httpsession,httpservletrequest,httpservletrespon 为什么默认就有?
然后我就找到了一些文章 https://my.oschina.net/lichhao?tab=newest&catalogId=285356
原文介绍的比较详细,找了一些对自己有用的,摘抄下来。
1.先从springmvc 入口开始吧,我们先在web.xml里面配置了
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
从这里可以看出DispatcherServlet 这个类随着服务一起启动了。不难看出springmvc是一个原生的Servlet框架对象为依托,通过合理的抽象,制定了严谨的的处理流程。那么第一个问题有了答案。
那么,就该回想老师讲的servlet原理的。
- Servlet 通过调用 init () 方法进行初始化。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 通过调用 destroy() 方法终止(结束)。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
我在这贴上一段简单的servlet生命周期,如果不理解,可以去找一些servlet温故一些知识。
根据servlet的生命周期,那么我就应该从init开始
SpringMVC初始化
springmvc初始化的时候都做了点什么呢?
我们先找init方法进入 DispatcherServlet类,搜索init方法,没有找到,那么就他的父级
DispatcherServlet-->FrameworkServlet-->HttpServletBean
下面就一一介绍这三个类
1.HttpServletBean
主要工作:工作是一些初始化的工作,将web.xml中配置的参数设置到Servlet中。比如servlet标签的子标签init-param标签中配置的参数。从DisPatcherServlet一直到HttpServletBean找到了init方法 下面贴一下源码
public final void init() throws ServletException {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Initializing servlet '" + this.getServletName() + "'");
}
try {
// getServletConfig 从web.xml找到配置参数并设置到ServletConfigPropertyValues内部
PropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);
// 使用BeanWrapper 构造DisPatchServlet
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));
this.initBeanWrapper(bw);
bw.setPropertyValues(pvs, true); // 设置DisPatcherServlet属性
} catch (BeansException var4) {
if(this.logger.isErrorEnabled()) {
this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);
}
throw var4;
}
this.initServletBean(); // 默认不做处理,方便子类继承之后做更多的处理
if(this.logger.isDebugEnabled()) {
this.logger.debug("Servlet '" + this.getServletName() + "' configured successfully");
}
}
然后initServletBean()开始拓展
2.FrameworkServlet
主要工作:将Servlet与Spring容器上下文关联。其实也就是初始化FrameworkServlet的属性webApplicationContext,这个属性代表SpringMVC上下文,它有个父类上下文,既web.xml中配置的ContextLoaderListener监听器初始化的容器上下文。FrameworkServlet继承了httpservletBean 并且重写了initServletBean这个方法
这个时候想:配置在Controller上的那些参数什么RequestMapping之类的
protected final void initServletBean() throws ServletException {
this.getServletContext().log("Initializing Spring FrameworkServlet '" + this.getServletName() + "'");
if(this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
// 初始化webApplicationContext属性
// webApplicationContext 是继承ApplicationContext的接口
// 该属性就是Spring容器上下文
// FeameworkServlet的作用就是把servlet跟spring容器关联
this.webApplicationContext = this.initWebApplicationContext();
//为做任何处理,方便子类继承做很多的处理
// 不过DispatcherServlet没有重新此方法
this.initFrameworkServlet();
} catch (ServletException var5) {
this.logger.error("Context initialization failed", var5);
throw var5;
} catch (RuntimeException var6) {
this.logger.error("Context initialization failed", var6);
throw var6;
}
if(this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + this.getServletName() + "': initialization completed in " + elapsedTime + " ms");
}
}
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.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) {
cwac.setParent(rootContext);
}
this.configureAndRefreshWebApplicationContext(cwac);
}
}
}
if(wac == null) {
wac = this.findWebApplicationContext();
}
if(wac == null) {
wac = this.createWebApplicationContext(rootContext);
}
if(!this.refreshEventReceived) {
this.onRefresh(wac);
}
if(this.publishContext) {
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
this.onRefresh这个方法并没有做任何处理,方便子类继承,做更多的处理;
3.DispatcherServlet
主要工作:初始化各个功能的实现类。比如异常处理、视图处理、请求映射处理等。DispatcherServlet重写了onRefresh这个方法
protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
上面就是Spring进行处理的事了
很明显,initStrategies方法内部会初始化各个策略接口的实现类。
比如异常处理初始化initHandlerExceptionResolvers方法:SpringMVC异常处理机制详解
视图处理初始化initViewResolvers方法:SpringMVC视图机制详解
请求映射处理初始化initHandlerMappings方法:详解SpringMVC请求的时候是如何找到正确的Controller
这个时候,1,2 这两个问题,在自己心里,已经有了大概的答案。
SpringMVC对扩展开放,对修改封闭
- 类中所有的变量声明,几乎都以接口的形式给出,并没有绑定在具体的实现类上。
- 使用模版方法模式,在父类中对基础行为进行定义,让子类实现模版方法扩展行为。