Spring MVC之FrameworkServlet源码分析

FrameworkServlet是HttpServletBean的子类,实现了HttpServletBean 的 initServletBean 方法。

通过initServletBean()进行WebApplicationContext初始化,其源码为:

 

 1     /**
 2      * Overridden method of {@link HttpServletBean}, invoked after any bean properties
 3      * have been set. Creates this servlet's WebApplicationContext.
 4      */
 5     @Override
 6     protected final void initServletBean() throws ServletException {
 7         getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
 8         if (this.logger.isInfoEnabled()) {
 9             this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
10         }
11         long startTime = System.currentTimeMillis();
12 
13         try {
14             this.webApplicationContext = initWebApplicationContext();
15             initFrameworkServlet();
16         }
17         catch (ServletException ex) {
18             this.logger.error("Context initialization failed", ex);
19             throw ex;
20         }
21         catch (RuntimeException ex) {
22             this.logger.error("Context initialization failed", ex);
23             throw ex;
24         }
25 
26         if (this.logger.isInfoEnabled()) {
27             long elapsedTime = System.currentTimeMillis() - startTime;
28             this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
29                     elapsedTime + " ms");
30         }
31     }

其主要的功能就是调用initWebApplicationContext方法初始化一个WebApplicationContext。

以下是initWebApplicationContext的源码:

 1     /**
 2      * Initialize and publish the WebApplicationContext for this servlet.
 3      * <p>Delegates to {@link #createWebApplicationContext} for actual creation
 4      * of the context. Can be overridden in subclasses.
 5      * @return the WebApplicationContext instance
 6      * @see #FrameworkServlet(WebApplicationContext)
 7      * @see #setContextClass
 8      * @see #setContextConfigLocation
 9      */
10     protected WebApplicationContext initWebApplicationContext() {
11         //1.取得根容器
12         WebApplicationContext rootContext =
13                 WebApplicationContextUtils.getWebApplicationContext(getServletContext());
14         WebApplicationContext wac = null;
15 
16         //2.取得 SpringMVC 容器
17         if (this.webApplicationContext != null) {
18             // A context instance was injected at construction time -> use it
19             wac = this.webApplicationContext;
20             if (wac instanceof ConfigurableWebApplicationContext) {
21                 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
22                 if (!cwac.isActive()) {
23                     // The context has not yet been refreshed -> provide services such as
24                     // setting the parent context, setting the application context id, etc
25                     if (cwac.getParent() == null) {
26                         // The context instance was injected without an explicit parent -> set
27                         // the root application context (if any; may be null) as the parent
28                         cwac.setParent(rootContext);
29                     }
30                     configureAndRefreshWebApplicationContext(cwac);
31                 }
32             }
33         }
34         
35         //3.寻找 SpringMVC 容器
36         if (wac == null) {
37             // No context instance was injected at construction time -> see if one
38             // has been registered in the servlet context. If one exists, it is assumed
39             // that the parent context (if any) has already been set and that the
40             // user has performed any initialization such as setting the context id
41             wac = findWebApplicationContext();
42         }
43         
44         // 4.创建 SpringMVC 容器
45         if (wac == null) {
46             // No context instance is defined for this servlet -> create a local one
47             wac = createWebApplicationContext(rootContext);
48         }
49 
50         // 5.重刷新 SpringMVC 容器
51         if (!this.refreshEventReceived) {
52             // Either the context is not a ConfigurableApplicationContext with refresh
53             // support or the context injected at construction time had already been
54             // refreshed -> trigger initial onRefresh manually here.
55             onRefresh(wac);
56         }
57 
58         // 6.发布 SpringMVC 容器
59         if (this.publishContext) {
60             // Publish the context as a servlet context attribute.
61             String attrName = getServletContextAttributeName();
62             getServletContext().setAttribute(attrName, wac);
63             if (this.logger.isDebugEnabled()) {
64                 this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
65                         "' as ServletContext attribute with name [" + attrName + "]");
66             }
67         }
68 
69         return wac;
70     }

 

若在 Servlet、ServletContext 中均没有找到 SpringMVC 容器,说明它还没被创建。创建过程的源码为:

 1     /**
 2      * Instantiate the WebApplicationContext for this servlet, either a default
 3      * {@link org.springframework.web.context.support.XmlWebApplicationContext}
 4      * or a {@link #setContextClass custom context class}, if set.
 5      * Delegates to #createWebApplicationContext(ApplicationContext).
 6      * @param parent the parent WebApplicationContext to use, or {@code null} if none
 7      * @return the WebApplicationContext for this servlet
 8      * @see org.springframework.web.context.support.XmlWebApplicationContext
 9      * @see #createWebApplicationContext(ApplicationContext)
10      */
11     protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
12         return createWebApplicationContext((ApplicationContext) parent);
13     }
14     
15     
16     
17     /**
18      * Instantiate the WebApplicationContext for this servlet, either a default
19      * {@link org.springframework.web.context.support.XmlWebApplicationContext}
20      * or a {@link #setContextClass custom context class}, if set.
21      * <p>This implementation expects custom contexts to implement the
22      * {@link org.springframework.web.context.ConfigurableWebApplicationContext}
23      * interface. Can be overridden in subclasses.
24      * <p>Do not forget to register this servlet instance as application listener on the
25      * created context (for triggering its {@link #onRefresh callback}, and to call
26      * {@link org.springframework.context.ConfigurableApplicationContext#refresh()}
27      * before returning the context instance.
28      * @param parent the parent ApplicationContext to use, or {@code null} if none
29      * @return the WebApplicationContext for this servlet
30      * @see org.springframework.web.context.support.XmlWebApplicationContext
31      */
32     protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
33         Class<?> contextClass = getContextClass();
34         if (this.logger.isDebugEnabled()) {
35             this.logger.debug("Servlet with name '" + getServletName() +
36                     "' will try to create custom WebApplicationContext context of class '" +
37                     contextClass.getName() + "'" + ", using parent context [" + parent + "]");
38         }
39         if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
40             throw new ApplicationContextException(
41                     "Fatal initialization error in servlet with name '" + getServletName() +
42                     "': custom WebApplicationContext class [" + contextClass.getName() +
43                     "] is not of type ConfigurableWebApplicationContext");
44         }
45         // 创建容器
46         ConfigurableWebApplicationContext wac =
47                 (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
48 
49         // 初始化容器
50         wac.setEnvironment(getEnvironment());
51         wac.setParent(parent);
52         wac.setConfigLocation(getContextConfigLocation());
53 
54         configureAndRefreshWebApplicationContext(wac);
55 
56         return wac;
57     }

 BeanUtils.instantiateClass 方法负责容器的真正创建过程,其源码为:

 1     /**
 2      * Instantiate a class using its no-arg constructor.
 3      * <p>Note that this method tries to set the constructor accessible
 4      * if given a non-accessible (that is, non-public) constructor.
 5      * @param clazz class to instantiate
 6      * @return the new instance
 7      * @throws BeanInstantiationException if the bean cannot be instantiated
 8      * @see Constructor#newInstance
 9      */
10     public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
11         Assert.notNull(clazz, "Class must not be null");
12         if (clazz.isInterface()) {
13             throw new BeanInstantiationException(clazz, "Specified class is an interface");
14         }
15         try {
16             // 利用反射实例化对象,完成容器创建
17             return instantiateClass(clazz.getDeclaredConstructor());
18         }
19         catch (NoSuchMethodException ex) {
20             throw new BeanInstantiationException(clazz, "No default constructor found", ex);
21         }
22     }
23     
24     
25     
26     /**
27      * Convenience method to instantiate a class using the given constructor.
28      * <p>Note that this method tries to set the constructor accessible if given a
29      * non-accessible (that is, non-public) constructor.
30      * @param ctor the constructor to instantiate
31      * @param args the constructor arguments to apply
32      * @return the new instance
33      * @throws BeanInstantiationException if the bean cannot be instantiated
34      * @see Constructor#newInstance
35      */
36     public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
37         Assert.notNull(ctor, "Constructor must not be null");
38         try {
39             // 设置访问权限为 public
40             ReflectionUtils.makeAccessible(ctor);
41             // 利用构造函数实例化对象
42             return ctor.newInstance(args);
43         }
44         catch (InstantiationException ex) {
45             throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
46         }
47         catch (IllegalAccessException ex) {
48             throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
49         }
50         catch (IllegalArgumentException ex) {
51             throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
52         }
53         catch (InvocationTargetException ex) {
54             throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
55         }
56     }

 onRefresh 方法为空方法,由子类 DispatcherServlet 来实现。

 

转载于:https://www.cnblogs.com/smile_to_warm/p/8998987.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值