@@ -136,9 +136,10 @@ public class ContextLoader {
136
136
137
137
static {
138
138
// 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配置文件中读取默认实现类
141
141
try {
142
+ // DEFAULT_STRATEGIES_PATH = "ContextLoader.properties"
142
143
ClassPathResource resource = new ClassPathResource (DEFAULT_STRATEGIES_PATH , ContextLoader .class );
143
144
defaultStrategies = PropertiesLoaderUtils .loadProperties (resource );
144
145
}
@@ -247,6 +248,8 @@ public void setContextInitializers(@Nullable ApplicationContextInitializer<?>...
247
248
248
249
249
250
/**
251
+ * 通过ServletContext对象初始化Spring的WebApplicationContext(父容器)
252
+ * 该方法在ServletContext启动之后被调用,并准备好处理客户端请求
250
253
* Initialize Spring's web application context for the given servlet context,
251
254
* using the application context provided at construction time, or creating a new one
252
255
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
@@ -258,6 +261,8 @@ public void setContextInitializers(@Nullable ApplicationContextInitializer<?>...
258
261
* @see #CONFIG_LOCATION_PARAM
259
262
*/
260
263
public WebApplicationContext initWebApplicationContext (ServletContext servletContext ) {
264
+ // web.xml中存在多次ContextLoader定义就会抛出异常
265
+ // WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE=org.springframework.web.context.WebApplicationContext.ROOT
261
266
if (servletContext .getAttribute (WebApplicationContext .ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE ) != null ) {
262
267
throw new IllegalStateException (
263
268
"Cannot initialize context because there is already a root application context present - " +
@@ -272,9 +277,9 @@ public WebApplicationContext initWebApplicationContext(ServletContext servletCon
272
277
long startTime = System .currentTimeMillis ();
273
278
274
279
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.
277
281
if (this .context == null ) {
282
+ // 创建Spring的WebApplicationContext
278
283
this .context = createWebApplicationContext (servletContext );
279
284
}
280
285
if (this .context instanceof ConfigurableWebApplicationContext ) {
@@ -283,21 +288,24 @@ public WebApplicationContext initWebApplicationContext(ServletContext servletCon
283
288
// The context has not yet been refreshed -> provide services such as
284
289
// setting the parent context, setting the application context id, etc
285
290
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
288
293
ApplicationContext parent = loadParentContext (servletContext );
289
294
cwac .setParent (parent );
290
295
}
296
+ // 设置cwac相关属性并调用refresh
291
297
configureAndRefreshWebApplicationContext (cwac , servletContext );
292
298
}
293
299
}
300
+ // 记录在servletContext中
294
301
servletContext .setAttribute (WebApplicationContext .ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE , this .context );
295
302
296
303
ClassLoader ccl = Thread .currentThread ().getContextClassLoader ();
297
304
if (ccl == ContextLoader .class .getClassLoader ()) {
298
305
currentContext = this .context ;
299
306
}
300
307
else if (ccl != null ) {
308
+ // 映射当前的类加载器与创建的实例到全局变量currentContextPerThread中
301
309
currentContextPerThread .put (ccl , this .context );
302
310
}
303
311
@@ -316,6 +324,7 @@ else if (ccl != null) {
316
324
}
317
325
318
326
/**
327
+ * 创建WebApplicationContext
319
328
* Instantiate the root WebApplicationContext for this loader, either the
320
329
* default context class or a custom context class if specified.
321
330
* <p>This implementation expects custom contexts to implement the
@@ -328,6 +337,7 @@ else if (ccl != null) {
328
337
* @see ConfigurableWebApplicationContext
329
338
*/
330
339
protected WebApplicationContext createWebApplicationContext (ServletContext sc ) {
340
+ // 判断WebApplicationContext具体要创建的子类类型
331
341
Class <?> contextClass = determineContextClass (sc );
332
342
if (!ConfigurableWebApplicationContext .class .isAssignableFrom (contextClass )) {
333
343
throw new ApplicationContextException ("Custom context class [" + contextClass .getName () +
@@ -337,6 +347,7 @@ protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
337
347
}
338
348
339
349
/**
350
+ * 判断决定WebApplicationContext具体要创建的子类类型
340
351
* Return the WebApplicationContext implementation class to use, either the
341
352
* default XmlWebApplicationContext or a custom context class if specified.
342
353
* @param servletContext current servlet context
@@ -345,7 +356,9 @@ protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
345
356
* @see org.springframework.web.context.support.XmlWebApplicationContext
346
357
*/
347
358
protected Class <?> determineContextClass (ServletContext servletContext ) {
359
+ // 获取ServletContext名称为“contextClass”的初始化参数的值
348
360
String contextClassName = servletContext .getInitParameter (CONTEXT_CLASS_PARAM );
361
+ // 如果web.xml中指定了WebApplicationContext具体要创建的子类类型,就用指定的,否则采用默认的
349
362
if (contextClassName != null ) {
350
363
try {
351
364
return ClassUtils .forName (contextClassName , ClassUtils .getDefaultClassLoader ());
@@ -356,6 +369,7 @@ protected Class<?> determineContextClass(ServletContext servletContext) {
356
369
}
357
370
}
358
371
else {
372
+ // 默认是org.springframework.web.context.support.XmlWebApplicationContext类型
359
373
contextClassName = defaultStrategies .getProperty (WebApplicationContext .class .getName ());
360
374
try {
361
375
return ClassUtils .forName (contextClassName , ContextLoader .class .getClassLoader ());
@@ -367,22 +381,30 @@ protected Class<?> determineContextClass(ServletContext servletContext) {
367
381
}
368
382
}
369
383
384
+ /**
385
+ * 配置并刷新WebApplicationContext
386
+ * @param wac
387
+ * @param sc
388
+ */
370
389
protected void configureAndRefreshWebApplicationContext (ConfigurableWebApplicationContext wac , ServletContext sc ) {
371
390
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配置了则使用配置,否则默认规则起名
374
393
String idParam = sc .getInitParameter (CONTEXT_ID_PARAM );
375
394
if (idParam != null ) {
376
395
wac .setId (idParam );
377
396
}
378
397
else {
379
- // Generate default id...
398
+ // 生成默认id替换,WebApplicationContext全限定类名+":"+项目名
380
399
wac .setId (ConfigurableWebApplicationContext .APPLICATION_CONTEXT_ID_PREFIX +
381
400
ObjectUtils .getDisplayString (sc .getContextPath ()));
382
401
}
383
402
}
384
403
404
+ // 将ServletContext设置给Spring容器
385
405
wac .setServletContext (sc );
406
+
407
+ // 设置Spring容器的配置文件路径
386
408
String configLocationParam = sc .getInitParameter (CONFIG_LOCATION_PARAM );
387
409
if (configLocationParam != null ) {
388
410
wac .setConfigLocation (configLocationParam );
@@ -397,6 +419,8 @@ protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicati
397
419
}
398
420
399
421
customizeContext (sc , wac );
422
+
423
+ // 调用Spring容器的refresh()方法,加载配置文件
400
424
wac .refresh ();
401
425
}
402
426
0 commit comments