Commit 2574ac2c by SunWei峰

初识Spring MVC

parent 8b079d43
# Spring源码分析 # Spring源码分析
*** ***
> 说明: 个人学习 Spring 源码,仅供自己学习使用,其中不以任何方式谋取利益, > 说明: <br>
> 有需要的同学们可以自行下载。 > 个人学习 Spring 源码,仅供自己学习使用,其中不以任何方式谋取利益。<br>
> 学习过程可能引用到某些博客中的信息,书籍中的信息。 > 未对源码做任何修改,只是在学习时加入自己理解的注解(部分参照网络博客)。<br>
> 如果涉嫌侵权,请联系本人立即删除。 > 有需要的同学们可以自行拉取。<br>
> 学习过程可能引用到某些博客中的信息,书籍中的信息。<br>
> 如果涉嫌侵权,请联系本人立即删除。<br>
> 如有需要某些资源(不违反任何规定情况下)可联系我给大家分享。<br>
`联系邮箱``osfung@163.com` `联系邮箱``osfung@163.com`
...@@ -12,6 +14,8 @@ ...@@ -12,6 +14,8 @@
源码获取方式:github 官方获取 源码获取方式:github 官方获取
源码地址:https://github.com/spring-projects/spring-framework
Spring版本:6.0.0 Spring版本:6.0.0
Java版本:JDK17 Java版本:JDK 17
\ No newline at end of file \ No newline at end of file
...@@ -257,6 +257,8 @@ public class ContextLoader { ...@@ -257,6 +257,8 @@ public class ContextLoader {
* @see #CONFIG_LOCATION_PARAM * @see #CONFIG_LOCATION_PARAM
*/ */
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// 初始化完成的 webApplicationContext 会被保存到 servletContext 的属性中,key 为 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
// 所以这里是判断是否已经初始化了webApplicationContext,就抛出异常(web.xml 中声明了多次ContextLoader 的定义),不可重复初始化。
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException( throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " + "Cannot initialize context because there is already a root application context present - " +
...@@ -289,6 +291,7 @@ public class ContextLoader { ...@@ -289,6 +291,7 @@ public class ContextLoader {
} }
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
// 映射当前的类加载器 与 创建的实例到全局变量 currentContextPerThread 中。
ClassLoader ccl = Thread.currentThread().getContextClassLoader(); ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) { if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context; currentContext = this.context;
...@@ -341,6 +344,7 @@ public class ContextLoader { ...@@ -341,6 +344,7 @@ public class ContextLoader {
* @see org.springframework.web.context.support.XmlWebApplicationContext * @see org.springframework.web.context.support.XmlWebApplicationContext
*/ */
protected Class<?> determineContextClass(ServletContext servletContext) { protected Class<?> determineContextClass(ServletContext servletContext) {
// 获取 contextClassName。第一次初始化自然是没有缓存的
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) { if (contextClassName != null) {
try { try {
...@@ -352,6 +356,8 @@ public class ContextLoader { ...@@ -352,6 +356,8 @@ public class ContextLoader {
} }
} }
else { else {
// 默认策略获取 contextClassName。通过上面的静态代码块我们可以知道defaultStrategies 读取的是 ContextLoader.properties 文件中的内容
// 默认是 XmlWebApplicationContext
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try { try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
......
...@@ -94,6 +94,8 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte ...@@ -94,6 +94,8 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte
} }
// 容器启动时会调用
// TODO: 2022/10/5 contextInitialized 在这儿
/** /**
* Initialize the root web application context. * Initialize the root web application context.
*/ */
......
...@@ -160,6 +160,7 @@ import org.springframework.web.util.WebUtils; ...@@ -160,6 +160,7 @@ import org.springframework.web.util.WebUtils;
* @see org.springframework.web.servlet.mvc.Controller * @see org.springframework.web.servlet.mvc.Controller
* @see org.springframework.web.context.ContextLoaderListener * @see org.springframework.web.context.ContextLoaderListener
*/ */
// DispatcherServlet 在这儿,init() 方法在父类 HttpServletBean 中
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet { public class DispatcherServlet extends FrameworkServlet {
...@@ -492,14 +493,23 @@ public class DispatcherServlet extends FrameworkServlet { ...@@ -492,14 +493,23 @@ public class DispatcherServlet extends FrameworkServlet {
* <p>May be overridden in subclasses in order to initialize further strategy objects. * <p>May be overridden in subclasses in order to initialize further strategy objects.
*/ */
protected void initStrategies(ApplicationContext context) { protected void initStrategies(ApplicationContext context) {
// 初始化多文件上传解析器
initMultipartResolver(context); initMultipartResolver(context);
// 初始化国际化解析器
initLocaleResolver(context); initLocaleResolver(context);
// 初始化主题解析器
initThemeResolver(context); initThemeResolver(context);
// 初始化 HandlerMapping
initHandlerMappings(context); initHandlerMappings(context);
// 初始化 HandlerAdapter
initHandlerAdapters(context); initHandlerAdapters(context);
// 初始化 Handler异常解析器
initHandlerExceptionResolvers(context); initHandlerExceptionResolvers(context);
// 初始化RequestToViewNameTranslator
initRequestToViewNameTranslator(context); initRequestToViewNameTranslator(context);
// 初始化 视图解析器
initViewResolvers(context); initViewResolvers(context);
// 初始化 FlashMapManager
initFlashMapManager(context); initFlashMapManager(context);
} }
...@@ -509,6 +519,10 @@ public class DispatcherServlet extends FrameworkServlet { ...@@ -509,6 +519,10 @@ public class DispatcherServlet extends FrameworkServlet {
* no multipart handling is provided. * no multipart handling is provided.
*/ */
private void initMultipartResolver(ApplicationContext context) { private void initMultipartResolver(ApplicationContext context) {
// 在 Spring 中,MultipartResolver 主要用来处理文件上传。默认情况下,Spring是没有 Multipart 处理的。
// 如果想使用 Spring 的 Multipart,则需要手动注入 Multipart 解析器,即MultipartResolver。
// 这样Spring 会检查每个请求是否包含 Multipart,如果包含,那么 MultipartResolver 就会解析它。
// 一般我们可以注入 CommonsMultipartResolver。
try { try {
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class); this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
...@@ -533,6 +547,7 @@ public class DispatcherServlet extends FrameworkServlet { ...@@ -533,6 +547,7 @@ public class DispatcherServlet extends FrameworkServlet {
* we default to AcceptHeaderLocaleResolver. * we default to AcceptHeaderLocaleResolver.
*/ */
private void initLocaleResolver(ApplicationContext context) { private void initLocaleResolver(ApplicationContext context) {
// 一共有三种实现类,一种使用 URL 后缀类型,一种基于 cookie 实现,一种基于 session 来实现
try { try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class); this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
...@@ -558,6 +573,7 @@ public class DispatcherServlet extends FrameworkServlet { ...@@ -558,6 +573,7 @@ public class DispatcherServlet extends FrameworkServlet {
* we default to a FixedThemeResolver. * we default to a FixedThemeResolver.
*/ */
private void initThemeResolver(ApplicationContext context) { private void initThemeResolver(ApplicationContext context) {
// 通过主题来改变用户体验,三种实现类:固定主题、主题保存在 session 中、主题保存在 cookie 中。
try { try {
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class); this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
...@@ -583,19 +599,24 @@ public class DispatcherServlet extends FrameworkServlet { ...@@ -583,19 +599,24 @@ public class DispatcherServlet extends FrameworkServlet {
* we default to BeanNameUrlHandlerMapping. * we default to BeanNameUrlHandlerMapping.
*/ */
private void initHandlerMappings(ApplicationContext context) { private void initHandlerMappings(ApplicationContext context) {
// 映射器可以有多个,在选用时会进行优先级排序,依次调用映射器链,找到就会直接返回处理器路径。
this.handlerMappings = null; this.handlerMappings = null;
// 如果启用所有的HandlerMapping。可以通过这个参数来控制是使用指定的HandlerMapping,还是检索所有的
if (this.detectAllHandlerMappings) { if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts. // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 寻找所有的 HandlerMapping 类型的类
Map<String, HandlerMapping> matchingBeans = Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) { if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values()); this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order. // We keep HandlerMappings in sorted order.
// 按照优先级进行排序
AnnotationAwareOrderComparator.sort(this.handlerMappings); AnnotationAwareOrderComparator.sort(this.handlerMappings);
} }
} }
else { else {
// 如果使用指定的参数,从容器中获取 beanName 为 "handlerMapping" 的 HandlerMapping
try { try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm); this.handlerMappings = Collections.singletonList(hm);
...@@ -607,6 +628,7 @@ public class DispatcherServlet extends FrameworkServlet { ...@@ -607,6 +628,7 @@ public class DispatcherServlet extends FrameworkServlet {
// Ensure we have at least one HandlerMapping, by registering // Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found. // a default HandlerMapping if no other mappings are found.
// 如果 handlerMappings 为null。则使用默认策略指定的HandlerMapping
if (this.handlerMappings == null) { if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
...@@ -870,8 +892,11 @@ public class DispatcherServlet extends FrameworkServlet { ...@@ -870,8 +892,11 @@ public class DispatcherServlet extends FrameworkServlet {
} }
} }
// 获取Name
String key = strategyInterface.getName(); String key = strategyInterface.getName();
// 从配置文件中获取 value
String value = defaultStrategies.getProperty(key); String value = defaultStrategies.getProperty(key);
// 获取到 value 之后就是对 value 的处理,添加返回。
if (value != null) { if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value); String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<>(classNames.length); List<T> strategies = new ArrayList<>(classNames.length);
......
...@@ -528,7 +528,9 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic ...@@ -528,7 +528,9 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
try { try {
// 委托给 initWebApplicationContext 方法来完成进一步的初始化
this.webApplicationContext = initWebApplicationContext(); this.webApplicationContext = initWebApplicationContext();
// 留给子类覆盖操作
initFrameworkServlet(); initFrameworkServlet();
} }
catch (ServletException | RuntimeException ex) { catch (ServletException | RuntimeException ex) {
...@@ -563,6 +565,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic ...@@ -563,6 +565,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null; WebApplicationContext wac = null;
// 1. 如果 webApplicationContext 在构造函数的时候被注入,则 wac != null, 则可以直接使用
if (this.webApplicationContext != null) { if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it // A context instance was injected at construction time -> use it
wac = this.webApplicationContext; wac = this.webApplicationContext;
...@@ -574,9 +577,11 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic ...@@ -574,9 +577,11 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
// the root application context (if any; may be null) as the parent // the root application context (if any; may be null) as the parent
cwac.setParent(rootContext); cwac.setParent(rootContext);
} }
// 2.刷新上下文环境
configureAndRefreshWebApplicationContext(cwac); configureAndRefreshWebApplicationContext(cwac);
} }
} }
// 3. 如果构造函数并没有注入,则wac为null,根据 contextAttribute 属性加载 WebApplicationContext
if (wac == null) { if (wac == null) {
// No context instance was injected at construction time -> see if one // No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed // has been registered in the servlet context. If one exists, it is assumed
...@@ -584,8 +589,10 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic ...@@ -584,8 +589,10 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
// user has performed any initialization such as setting the context id // user has performed any initialization such as setting the context id
wac = findWebApplicationContext(); wac = findWebApplicationContext();
} }
// 4. 如果上面两个方式都没有加载到 WebApplicationContext,则尝试自己加载
if (wac == null) { if (wac == null) {
// No context instance is defined for this servlet -> create a local one // No context instance is defined for this servlet -> create a local one
// 自己尝试创建WebApplicationContext
wac = createWebApplicationContext(rootContext); wac = createWebApplicationContext(rootContext);
} }
...@@ -594,6 +601,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic ...@@ -594,6 +601,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
// support or the context injected at construction time had already been // support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here. // refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) { synchronized (this.onRefreshMonitor) {
// 5.刷新
onRefresh(wac); onRefresh(wac);
} }
} }
...@@ -659,15 +667,18 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic ...@@ -659,15 +667,18 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
wac.setEnvironment(getEnvironment()); wac.setEnvironment(getEnvironment());
wac.setParent(parent); wac.setParent(parent);
// 获取web.xml 配置的 DispatcherServlet init-params contextConfigLocation 属性
String configLocation = getContextConfigLocation(); String configLocation = getContextConfigLocation();
if (configLocation != null) { if (configLocation != null) {
wac.setConfigLocation(configLocation); wac.setConfigLocation(configLocation);
} }
// 配置 WebApplicationContext 实例并刷新
configureAndRefreshWebApplicationContext(wac); configureAndRefreshWebApplicationContext(wac);
return wac; return wac;
} }
// 已经创建的 WebApplicationContext 实例进行配置及刷新。其实就是配置并刷新Spring。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value // The application context id is still set to its original default value
...@@ -682,6 +693,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic ...@@ -682,6 +693,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
} }
} }
// 设置一些属性,ServletContext、ServletConfig等
wac.setServletContext(getServletContext()); wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig()); wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace()); wac.setNamespace(getNamespace());
......
...@@ -148,12 +148,16 @@ public abstract class HttpServletBean extends HttpServlet implements Environment ...@@ -148,12 +148,16 @@ public abstract class HttpServletBean extends HttpServlet implements Environment
public final void init() throws ServletException { public final void init() throws ServletException {
// Set bean properties from init parameters. // Set bean properties from init parameters.
// 1. 封装及验证初始化参数
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) { if (!pvs.isEmpty()) {
try { try {
// 2. 将当前 Servlet 实例转化为 BeanWrapper 实例
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
// 3. 注册于相对于 Resource 的属性编辑器
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
// 4. 属性注入(支持 Spring 的自动注入)
initBeanWrapper(bw); initBeanWrapper(bw);
bw.setPropertyValues(pvs, true); bw.setPropertyValues(pvs, true);
} }
...@@ -166,6 +170,7 @@ public abstract class HttpServletBean extends HttpServlet implements Environment ...@@ -166,6 +170,7 @@ public abstract class HttpServletBean extends HttpServlet implements Environment
} }
// Let subclasses do whatever initialization they like. // Let subclasses do whatever initialization they like.
// 5. servletBean的初始化
initServletBean(); initServletBean();
} }
...@@ -220,10 +225,12 @@ public abstract class HttpServletBean extends HttpServlet implements Environment ...@@ -220,10 +225,12 @@ public abstract class HttpServletBean extends HttpServlet implements Environment
Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ? Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ?
new HashSet<>(requiredProperties) : null); new HashSet<>(requiredProperties) : null);
// 获取 web.xml 中 DispatcherServlet 配置的 init-params 属性内容
Enumeration<String> paramNames = config.getInitParameterNames(); Enumeration<String> paramNames = config.getInitParameterNames();
while (paramNames.hasMoreElements()) { while (paramNames.hasMoreElements()) {
String property = paramNames.nextElement(); String property = paramNames.nextElement();
Object value = config.getInitParameter(property); Object value = config.getInitParameter(property);
// 保存 init-params 属性
addPropertyValue(new PropertyValue(property, value)); addPropertyValue(new PropertyValue(property, value));
if (missingProps != null) { if (missingProps != null) {
missingProps.remove(property); missingProps.remove(property);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment