Skip to content

Commit 07b12ba

Browse files
committed
Spring源码关于Spring MVC部分中文注释
1 parent 50afd4c commit 07b12ba

File tree

21 files changed

+377
-42
lines changed

21 files changed

+377
-42
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,10 @@ protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredTy
284284
throw new BeanCurrentlyInCreationException(beanName);
285285
}
286286

287-
// Check if bean definition exists in this factory.
287+
// 查看其父容器是否存在,这就决定了Spring父子容器的可见特性
288288
BeanFactory parentBeanFactory = getParentBeanFactory();
289289

290-
// 如果beanDefinitionMap中也就是已经加载的类中不包括beanName则尝试从parentBeanFactory中检测
290+
// 如果beanDefinitionMap中也就是已经加载的类中不包括beanName则尝试从父容器parentBeanFactory中检测
291291
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
292292
// Not found -> check parent.
293293
String nameToLookup = originalBeanName(name);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package guo.ping.mvctest.context;
2+
3+
import javax.servlet.ServletContext;
4+
import javax.servlet.ServletContextEvent;
5+
import javax.servlet.ServletContextListener;
6+
7+
/**
8+
* @description:
9+
* @author: guoping wang
10+
* @date: 2018/11/19 10:36
11+
* @project: spring
12+
*/
13+
public class MyContextListener implements ServletContextListener {
14+
15+
private ServletContext servletContext;
16+
17+
@Override
18+
public void contextInitialized(ServletContextEvent sce) {
19+
servletContext = sce.getServletContext();
20+
servletContext.setAttribute("name", "=========wgp========");
21+
System.out.println("web application is starting...");
22+
}
23+
24+
@Override
25+
public void contextDestroyed(ServletContextEvent sce) {
26+
System.out.println("servlet context is going to shut down...");
27+
System.out.println(servletContext.getAttribute("name"));
28+
}
29+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package guo.ping.mvctest.controller;
2+
3+
import org.springframework.web.servlet.ModelAndView;
4+
import org.springframework.web.servlet.mvc.AbstractController;
5+
import org.springframework.web.servlet.mvc.LastModified;
6+
7+
import javax.servlet.http.HttpServletRequest;
8+
import javax.servlet.http.HttpServletResponse;
9+
10+
/**
11+
* @description: 测试Http缓存
12+
* @author: guoping wang
13+
* @date: 2018/11/21 11:18
14+
* @project: spring
15+
*/
16+
public class ModifyController extends AbstractController implements LastModified {
17+
18+
private long lastModified;
19+
20+
@Override
21+
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
22+
response.getWriter().write("test last modify");
23+
return null;
24+
}
25+
26+
@Override
27+
public long getLastModified(HttpServletRequest request) {
28+
if (lastModified == 0L) {
29+
lastModified = System.currentTimeMillis();
30+
}
31+
return lastModified;
32+
}
33+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package guo.ping.mvctest.interceptor;
2+
3+
import org.springframework.web.servlet.HandlerInterceptor;
4+
import org.springframework.web.servlet.ModelAndView;
5+
6+
import javax.servlet.http.HttpServletRequest;
7+
import javax.servlet.http.HttpServletResponse;
8+
9+
/**
10+
* @description:
11+
* @author: guoping wang
12+
* @date: 2018/11/21 16:10
13+
* @project: spring
14+
*/
15+
public class CountTimeInterceptor implements HandlerInterceptor {
16+
17+
@Override
18+
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
19+
long startTime = System.currentTimeMillis();
20+
request.setAttribute("startTime", startTime);
21+
return true;
22+
}
23+
24+
@Override
25+
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
26+
long startTime = (long) request.getAttribute("startTime");
27+
request.removeAttribute("startTime");
28+
long endTime = System.currentTimeMillis();
29+
modelAndView.addObject("handingTime", endTime - startTime);
30+
}
31+
32+
@Override
33+
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
34+
35+
}
36+
}

spring-mymvc/src/main/resources/springmvc-config.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,19 @@
77
<property name="mappings">
88
<props>
99
<prop key="/userlist">userController</prop>
10+
<prop key="/modify">modifyController</prop>
1011
</props>
1112
</property>
13+
<property name="interceptors">
14+
<list>
15+
<ref bean="countTimeInterceptor" />
16+
</list>
17+
</property>
1218
</bean>
1319

20+
<bean id="countTimeInterceptor" class="guo.ping.mvctest.interceptor.CountTimeInterceptor" />
21+
1422
<bean id="userController" class="guo.ping.mvctest.controller.UserController" />
23+
<bean id="modifyController" class="guo.ping.mvctest.controller.ModifyController" />
1524

1625
</beans>

spring-mymvc/src/main/webapp/WEB-INF/jsp/userlist.jsp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
  <c:out value="${user.username}"/><br/>
66
  <c:out value="${user.age}"/><br/>
77
</c:forEach>
8+
请求时间:${handingTime}

spring-web/src/main/java/org/springframework/web/context/ContextLoader.java

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,10 @@ public class ContextLoader {
136136

137137
static {
138138
// Load default strategy implementations from properties file.
139-
// This is currently strictly internal and not meant to be customized
140-
// by application developers.
139+
// This is currently strictly internal and not meant to be customized by application developers.
140+
// 从ContextLoader.properties配置文件中读取默认实现类
141141
try {
142+
// DEFAULT_STRATEGIES_PATH = "ContextLoader.properties"
142143
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
143144
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
144145
}
@@ -247,6 +248,8 @@ public void setContextInitializers(@Nullable ApplicationContextInitializer<?>...
247248

248249

249250
/**
251+
* 通过ServletContext对象初始化Spring的WebApplicationContext(父容器)
252+
* 该方法在ServletContext启动之后被调用,并准备好处理客户端请求
250253
* Initialize Spring's web application context for the given servlet context,
251254
* using the application context provided at construction time, or creating a new one
252255
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
@@ -258,6 +261,8 @@ public void setContextInitializers(@Nullable ApplicationContextInitializer<?>...
258261
* @see #CONFIG_LOCATION_PARAM
259262
*/
260263
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
264+
// web.xml中存在多次ContextLoader定义就会抛出异常
265+
// WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE=org.springframework.web.context.WebApplicationContext.ROOT
261266
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
262267
throw new IllegalStateException(
263268
"Cannot initialize context because there is already a root application context present - " +
@@ -272,9 +277,9 @@ public WebApplicationContext initWebApplicationContext(ServletContext servletCon
272277
long startTime = System.currentTimeMillis();
273278

274279
try {
275-
// Store context in local instance variable, to guarantee that
276-
// it is available on ServletContext shutdown.
280+
// Store context in local instance variable, to guarantee that it is available on ServletContext shutdown.
277281
if (this.context == null) {
282+
// 创建Spring的WebApplicationContext
278283
this.context = createWebApplicationContext(servletContext);
279284
}
280285
if (this.context instanceof ConfigurableWebApplicationContext) {
@@ -283,21 +288,24 @@ public WebApplicationContext initWebApplicationContext(ServletContext servletCon
283288
// The context has not yet been refreshed -> provide services such as
284289
// setting the parent context, setting the application context id, etc
285290
if (cwac.getParent() == null) {
286-
// The context instance was injected without an explicit parent ->
287-
// determine parent for root web application context, if any.
291+
// The context instance was injected without an explicit parent -> determine parent for root web application context, if any.
292+
// 看看是否有父容器,有的话设置给当前创建的容器,DispatcherServlet没有重写方法,直接返回null
288293
ApplicationContext parent = loadParentContext(servletContext);
289294
cwac.setParent(parent);
290295
}
296+
// 设置cwac相关属性并调用refresh
291297
configureAndRefreshWebApplicationContext(cwac, servletContext);
292298
}
293299
}
300+
// 记录在servletContext中
294301
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
295302

296303
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
297304
if (ccl == ContextLoader.class.getClassLoader()) {
298305
currentContext = this.context;
299306
}
300307
else if (ccl != null) {
308+
// 映射当前的类加载器与创建的实例到全局变量currentContextPerThread中
301309
currentContextPerThread.put(ccl, this.context);
302310
}
303311

@@ -316,6 +324,7 @@ else if (ccl != null) {
316324
}
317325

318326
/**
327+
* 创建WebApplicationContext
319328
* Instantiate the root WebApplicationContext for this loader, either the
320329
* default context class or a custom context class if specified.
321330
* <p>This implementation expects custom contexts to implement the
@@ -328,6 +337,7 @@ else if (ccl != null) {
328337
* @see ConfigurableWebApplicationContext
329338
*/
330339
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
340+
// 判断WebApplicationContext具体要创建的子类类型
331341
Class<?> contextClass = determineContextClass(sc);
332342
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
333343
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
@@ -337,6 +347,7 @@ protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
337347
}
338348

339349
/**
350+
* 判断决定WebApplicationContext具体要创建的子类类型
340351
* Return the WebApplicationContext implementation class to use, either the
341352
* default XmlWebApplicationContext or a custom context class if specified.
342353
* @param servletContext current servlet context
@@ -345,7 +356,9 @@ protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
345356
* @see org.springframework.web.context.support.XmlWebApplicationContext
346357
*/
347358
protected Class<?> determineContextClass(ServletContext servletContext) {
359+
// 获取ServletContext名称为“contextClass”的初始化参数的值
348360
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
361+
// 如果web.xml中指定了WebApplicationContext具体要创建的子类类型,就用指定的,否则采用默认的
349362
if (contextClassName != null) {
350363
try {
351364
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
@@ -356,6 +369,7 @@ protected Class<?> determineContextClass(ServletContext servletContext) {
356369
}
357370
}
358371
else {
372+
// 默认是org.springframework.web.context.support.XmlWebApplicationContext类型
359373
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
360374
try {
361375
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
@@ -367,22 +381,30 @@ protected Class<?> determineContextClass(ServletContext servletContext) {
367381
}
368382
}
369383

384+
/**
385+
* 配置并刷新WebApplicationContext
386+
* @param wac
387+
* @param sc
388+
*/
370389
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
371390
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
372-
// The application context id is still set to its original default value
373-
// -> assign a more useful id based on available information
391+
// The application context id is still set to its original default value -> assign a more useful id based on available information
392+
// 替换WebApplicationContext容器的id,起一个更有意义的名字。如果ServletContext配置了则使用配置,否则默认规则起名
374393
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
375394
if (idParam != null) {
376395
wac.setId(idParam);
377396
}
378397
else {
379-
// Generate default id...
398+
// 生成默认id替换,WebApplicationContext全限定类名+":"+项目名
380399
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
381400
ObjectUtils.getDisplayString(sc.getContextPath()));
382401
}
383402
}
384403

404+
// 将ServletContext设置给Spring容器
385405
wac.setServletContext(sc);
406+
407+
// 设置Spring容器的配置文件路径
386408
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
387409
if (configLocationParam != null) {
388410
wac.setConfigLocation(configLocationParam);
@@ -397,6 +419,8 @@ protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicati
397419
}
398420

399421
customizeContext(sc, wac);
422+
423+
// 调用Spring容器的refresh()方法,加载配置文件
400424
wac.refresh();
401425
}
402426

spring-web/src/main/java/org/springframework/web/context/ContextLoaderListener.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import javax.servlet.ServletContextListener;
2121

2222
/**
23+
* 启动Web容器时,自动装配ApplicationContext的配置信息
2324
* Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
2425
* Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
2526
*
@@ -97,15 +98,18 @@ public ContextLoaderListener(WebApplicationContext context) {
9798

9899
/**
99100
* Initialize the root web application context.
101+
* 该方法在ServletContext启动之后被调用,并准备好处理客户端请求
100102
*/
101103
@Override
102104
public void contextInitialized(ServletContextEvent event) {
105+
// 初始化WebApplicationContext
103106
initWebApplicationContext(event.getServletContext());
104107
}
105108

106109

107110
/**
108111
* Close the root web application context.
112+
* 这个方法在ServletContext将要关闭的时候调用
109113
*/
110114
@Override
111115
public void contextDestroyed(ServletContextEvent event) {

spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ public boolean checkNotModified(@Nullable String etag, long lastModifiedTimestam
233233

234234
boolean validated = validateIfNoneMatch(etag);
235235
if (!validated) {
236+
// 比较If-Modified-Since和lastModifiedTimestamp
236237
validateIfModifiedSince(lastModifiedTimestamp);
237238
}
238239

@@ -245,6 +246,7 @@ public boolean checkNotModified(@Nullable String etag, long lastModifiedTimestam
245246
}
246247
if (isHttpGetOrHead) {
247248
if (lastModifiedTimestamp > 0 && parseDateValue(response.getHeader(LAST_MODIFIED)) == -1) {
249+
// 更新Last-Modified为最新的更新时间
248250
response.setDateHeader(LAST_MODIFIED, lastModifiedTimestamp);
249251
}
250252
if (StringUtils.hasLength(etag) && response.getHeader(ETAG) == null) {
@@ -321,7 +323,7 @@ private boolean validateIfModifiedSince(long lastModifiedTimestamp) {
321323
if (ifModifiedSince == -1) {
322324
return false;
323325
}
324-
// We will perform this validation...
326+
// 如果当前请求中的If-Modified-Since时间晚于服务器时间,则认为是最新的,直接使用缓存
325327
this.notModified = ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000);
326328
return true;
327329
}

0 commit comments

Comments
 (0)