当前位置:   article > 正文

SpringMVC源码剖析-SpringMVC初始化,2024年最新java实施工程师面试

SpringMVC源码剖析-SpringMVC初始化,2024年最新java实施工程师面试

bw.setPropertyValues(pvs, true);

}

catch (BeansException ex) {

logger.error(“Failed to set bean properties on servlet '” + getServletName() + “'”, ex);

throw ex;

}

// Let subclasses do whatever initialization they like.

//【重要】初始化ServletBean

initServletBean();

if (logger.isDebugEnabled()) {

logger.debug(“Servlet '” + getServletName() + “’ configured successfully”);

}

}

init方法中调用initServletBean初始化ServletBean,继续跟踪下去,代码来到org.springframework.web.servlet.FrameworkServlet#initServletBean

protected final void initServletBean() throws ServletException {

getServletContext().log(“Initializing Spring FrameworkServlet '” + getServletName() + “'”);

if (this.logger.isInfoEnabled()) {

this.logger.info(“FrameworkServlet '” + getServletName() + “': initialization started”);

}

long startTime = System.currentTimeMillis();

try {

//【重要】这里在初始化WebApplicationContext

this.webApplicationContext = initWebApplicationContext();

//空方法,让子类来实现

initFrameworkServlet();

}

catch (ServletException ex) {

this.logger.error(“Context initialization failed”, ex);

throw ex;

}

catch (RuntimeException ex) {

this.logger.error(“Context initialization failed”, ex);

throw ex;

}

if (this.logger.isInfoEnabled()) {

long elapsedTime = System.currentTimeMillis() - startTime;

this.logger.info(“FrameworkServlet '” + getServletName() + "': initialization completed in " +

elapsedTime + " ms");

}

}

FrameworkServlet#initServletBean方法中调用initWebApplicationContext初始化IOC容器对象,在ContextLoaderListener中已经创建了WebApplicationContext , 这里只是做初始化。见:org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext

protected WebApplicationContext initWebApplicationContext() {

//【重要】从ServletContext中获取WebApplicationContext,也就是通过ContextLoadListener创建的

// rootContext 根容器,是从ServletContext中拿到的容器对象

WebApplicationContext

WebApplicationContext rootContext =

WebApplicationContextUtils.getWebApplicationContext(getServletContext());

WebApplicationContext wac = null;

if (this.webApplicationContext != null) {

// A context instance was injected at construction time -> use it

wac = this.webApplicationContext;

if (wac instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;

if (!cwac.isActive()) {

// The context has not yet been refreshed -> provide services such as

// setting the parent context, setting the application context id, etc

if (cwac.getParent() == null) {

// The context instance was injected without an explicit parent -> set

// the root application context (if any; may be null) as the parent

cwac.setParent(rootContext);

}

//【重要】刷新上下文,会走到ioc的 refresh();方法

configureAndRefreshWebApplicationContext(cwac);

}

}

}

if (wac == null) {

// No context instance was injected at construction time -> see if one

// has been registered in the servlet context. If one exists, it is assumed

// that the parent context (if any) has already been set and that the

// user has performed any initialization such as setting the context id

wac = findWebApplicationContext();

}

if (wac == null) {

//[重要]如果wac 为空,到这里还没有WebApplicationContext就会走

//FrameworkServlet#createWebApplicationContext,创建一个XmlWebApplicationContext

//然后执行 wac.setParent(parent); 形成一个父子容器 ,rootContext是针对SpringMVC的容器,wac是针对Spring的容器

//最后会走容器的Refresh刷新方法刷新容器

// No context instance is defined for this servlet -> create a local one

wac = createWebApplicationContext(rootContext);

}

if (!this.refreshEventReceived) {

// Either the context is not a ConfigurableApplicationContext with refresh

// support or the context injected at construction time had already been

// refreshed -> trigger initial onRefresh manually here.

//[重要]初始化SpringMVC核心组件

onRefresh(wac);

}

if (this.publishContext) {

//把context作为ServletContext中的属性

// Publish the context as a servlet context attribute.

String attrName = getServletContextAttributeName();

getServletContext().setAttribute(attrName, wac);

if (this.logger.isDebugEnabled()) {

this.logger.debug(“Published WebApplicationContext of servlet '” + getServletName() +

“’ as ServletContext attribute with name [” + attrName + “]”);

}

}

return wac;

}

initWebApplicationContext方法中从ServletContext中拿到WebApplicationContext作为rootContext根容器,然后会走configureAndRefreshWebApplicationContext方法创建一个新的WebApplicationContext作为子容器形成父子容器,最终调用容器的AbstractApplicationContext#refreshrefresh()刷新容器,这个在Spring源码分析中已经有说道。

刷新完成容器后,会调用 onRefresh(wac)方法; 见org.springframework.web.servlet.DispatcherServlet#onRefresh

/**

  • This implementation calls {@link #initStrategies}.

*/

@Override

protected void onRefresh(ApplicationContext context) {

initStrategies(context);

}

/**

  • Initialize the strategy objects that this servlet uses.

  • May be overridden in subclasses in order to initialize further strategy objects.

*/

protected void initStrategies(ApplicationContext context) {

//多文件上传的组件

initMultipartResolver(context);

//初始化本地语言环境

initLocaleResolver(context);

//初始化模板处理器

initThemeResolver(context);

//初始化handlerMapping

initHandlerMappings(context);

//初始化参数适配器

initHandlerAdapters(context);

//初始化异常拦截器

initHandlerExceptionResolvers(context);

//初始化视图预处理器

initRequestToViewNameTranslator(context);

//初始化视图转换器

initViewResolvers(context);

//FlashMap 管理器

initFlashMapManager(context);

}

initStrategies中初始化了SpringMVC最核心的九大组件

initMultipartResolver(context);

初始化文件上传的组件 ,MultipartResolver作为文件上传解析组件,如果开发中需要使用MultipartResolver需要在xml中配置<bean id="multipartResolver" class="org.Springframework.web.multipart.commons.CommonsMultipartResolver" /> , 这样请求中的multipart属性就会被处理。

private void initMultipartResolver(ApplicationContext context) {

try {

//从容器中查找Bean,如果在xml配置了这里就能获取到

this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);

if (logger.isDebugEnabled()) {

logger.debug(“Using MultipartResolver [” + this.multipartResolver + “]”);

}

}

catch (NoSuchBeanDefinitionException ex) {

// Default is no multipart resolver.

this.multipartResolver = null;

if (logger.isDebugEnabled()) {

logger.debug(“Unable to locate MultipartResolver with name '” + MULTIPART_RESOLVER_BEAN_NAME +

“': no multipart request handling provided”);

}

}

}

initLocaleResolver(context);

初始化本地语言环境 ,Spring国际化支持

private void initLocaleResolver(ApplicationContext context) {

try {

//从容器中查找localeResolver

this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);

if (logger.isDebugEnabled()) {

logger.debug(“Using LocaleResolver [” + this.localeResolver + “]”);

}

}

catch (NoSuchBeanDefinitionException ex) {

// We need to use the default.

//使用一个默认的localeResolver

this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);

if (logger.isDebugEnabled()) {

logger.debug(“Unable to locate LocaleResolver with name '” + LOCALE_RESOLVER_BEAN_NAME +

“': using default [” + this.localeResolver + “]”);

}

}

}

initThemeResolver(context);

初始化模板处理器 ,web开发中可以通过 Theme 来控 网页风格,改善应用程序的视觉

效果。

private void initThemeResolver(ApplicationContext context) {

try {

this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);

if (logger.isDebugEnabled()) {

logger.debug(“Using ThemeResolver [” + this.themeResolver + “]”);

}

}

catch (NoSuchBeanDefinitionException ex) {

// We need to use the default.

this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);

if (logger.isDebugEnabled()) {

logger.debug(

“Unable to locate ThemeResolver with name '” + THEME_RESOLVER_BEAN_NAME + “': using default [” +

this.themeResolver + “]”);

}

}

}

initHandlerMappings(context);

初始化handlerMapping ,HandlerMapping维护了URL和Handler(controller)的映射关系,当客户端发出请求, DispatcherServlet 会将 Request 提交 HandlerMapping,HanlerMapping 根据 Web Application Context 的配置查找相应的 Controller。

private void initHandlerMappings(ApplicationContext context) {

this.handlerMappings = null;

if (this.detectAllHandlerMappings) {

// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.

//[重要]查找所有的 HandlermApping

Map<String, HandlerMapping> matchingBeans =

BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

if (!matchingBeans.isEmpty()) {

//把handlerMapping存储到 handlerMappings ,一个ArrayList

this.handlerMappings = new ArrayList(matchingBeans.values());

// We keep HandlerMappings in sorted order.

//按照order排序,

OrderComparator.sort(this.handlerMappings);

}

}

else {

try {

HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);

this.handlerMappings = Collections.singletonList(hm);

}

catch (NoSuchBeanDefinitionException ex) {

// Ignore, we’ll add a default HandlerMapping later.

}

}

// Ensure we have at least one HandlerMapping, by registering

// a default HandlerMapping if no other mappings are found.

if (this.handlerMappings == null) {

this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);

if (logger.isDebugEnabled()) {

logger.debug(“No HandlerMappings found in servlet '” + getServletName() + “': using default”);

}

}

}

默认找到所有的HandlerMapping,查找Handler的时候,按照优先级去执行HandlerMapping,如果第一个HandlerMapping不能返回Handler就走第二个HandlerMapping以此类推。

initHandlerAdapters(context);

初始化参数适配器 ,这是个典型的适配器模式的使用,当DispatcherServlet从HandlerMapping中找到对应的Handler后, 会轮询HandlerAdapter模块,查找能够处理当前 HTTP 请求的处理器适配器的实现,然后去执行Handler得到ModelAndView。并把结果返回给DispatcherServlet。

private void initHandlerAdapters(ApplicationContext context) {

this.handlerAdapters = null;

if (this.detectAllHandlerAdapters) {

// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.

//查找所有到HandlerAdapters ,

Map<String, HandlerAdapter> matchingBeans =

BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);

if (!matchingBeans.isEmpty()) {

//添加到handlerAdapters,一个ArrayList

this.handlerAdapters = new ArrayList(matchingBeans.values());

// We keep HandlerAdapters in sorted order.

//按照order排序

OrderComparator.sort(this.handlerAdapters);

}

}

else {

try {

HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);

this.handlerAdapters = Collections.singletonList(ha);

}

catch (NoSuchBeanDefinitionException ex) {

// Ignore, we’ll add a default HandlerAdapter later.

}

}

// Ensure we have at least some HandlerAdapters, by registering

// default HandlerAdapters if no other adapters are found.

if (this.handlerAdapters == null) {

this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);

if (logger.isDebugEnabled()) {

logger.debug(“No HandlerAdapters found in servlet '” + getServletName() + “': using default”);

}

}

}

  • RequestMappingHandlerAdapter : HandlerAdapter实现的抽象基类,支持HandlerMethod类型的处理程序。

  • HttpRequestHandlerAdapter :HTTP 请求处理器适配器仅仅支持对 HTTP 请求处理 的适配 ,它简单地将 请求对象和响应对象传递给 HTTP 请求处理器HttpRequestHandler,它并不需要返回值 它主要应用在基于 HTTP

的远程调用的实现上

  • SimpleControllerHandlerAdapter:把http请求适配到控制器controller进行处理。

initHandlerExceptionResolvers(context);

初始化异常拦截器 ,基于 HandlerExceptionResolver 接口的异常处理,使用这种方式只需要实现resolveException方法,该方法根据异常生成一个ModeAndView ,如果该方法返 回了 null ,则 Spring 会继续寻找其他的实现了HandlerExceptionResolver 接口的 bean 。

private void initHandlerExceptionResolvers(ApplicationContext context) {

this.handlerExceptionResolvers = null;

if (this.detectAllHandlerExceptionResolvers) {

// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.

//查找所有的异常解析器

Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils

.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);

if (!matchingBeans.isEmpty()) {

this.handlerExceptionResolvers = new ArrayList(matchingBeans.values());

// We keep HandlerExceptionResolvers in sorted order.

//按照order优先级排序

OrderComparator.sort(this.handlerExceptionResolvers);

}

}

else {

try {

HandlerExceptionResolver her =

context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后

既已说到spring cloud alibaba,那对于整个微服务架构,如果想要进一步地向上提升自己,到底应该掌握哪些核心技能呢?

就个人而言,对于整个微服务架构,像RPC、Dubbo、Spring Boot、Spring Cloud Alibaba、Docker、kubernetes、Spring Cloud Netflix、Service Mesh等这些都是最最核心的知识,架构师必经之路!下图,是自绘的微服务架构路线体系大纲,如果有还不知道自己该掌握些啥技术的朋友,可根据小编手绘的大纲进行一个参考。

image

如果觉得图片不够清晰,也可来找小编分享原件的xmind文档!

且除此份微服务体系大纲外,我也有整理与其每个专题核心知识点对应的最强学习笔记:

  • 出神入化——SpringCloudAlibaba.pdf

  • SpringCloud微服务架构笔记(一).pdf

  • SpringCloud微服务架构笔记(二).pdf

  • SpringCloud微服务架构笔记(三).pdf

  • SpringCloud微服务架构笔记(四).pdf

  • Dubbo框架RPC实现原理.pdf

  • Dubbo最新全面深度解读.pdf

  • Spring Boot学习教程.pdf

  • SpringBoo核心宝典.pdf

  • 第一本Docker书-完整版.pdf

  • 使用SpringCloud和Docker实战微服务.pdf

  • K8S(kubernetes)学习指南.pdf

image

另外,如果不知道从何下手开始学习呢,小编这边也有对每个微服务的核心知识点手绘了其对应的知识架构体系大纲,不过全是导出的xmind文件,全部的源文件也都在此!

image

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

T7bxb-1712766978141)]

如果觉得图片不够清晰,也可来找小编分享原件的xmind文档!

且除此份微服务体系大纲外,我也有整理与其每个专题核心知识点对应的最强学习笔记:

  • 出神入化——SpringCloudAlibaba.pdf

  • SpringCloud微服务架构笔记(一).pdf

  • SpringCloud微服务架构笔记(二).pdf

  • SpringCloud微服务架构笔记(三).pdf

  • SpringCloud微服务架构笔记(四).pdf

  • Dubbo框架RPC实现原理.pdf

  • Dubbo最新全面深度解读.pdf

  • Spring Boot学习教程.pdf

  • SpringBoo核心宝典.pdf

  • 第一本Docker书-完整版.pdf

  • 使用SpringCloud和Docker实战微服务.pdf

  • K8S(kubernetes)学习指南.pdf

[外链图片转存中…(img-NJ5KWuEw-1712766978141)]

另外,如果不知道从何下手开始学习呢,小编这边也有对每个微服务的核心知识点手绘了其对应的知识架构体系大纲,不过全是导出的xmind文件,全部的源文件也都在此!

[外链图片转存中…(img-WPj8iePV-1712766978141)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-Na4skC3D-1712766978142)]

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/1015692
推荐阅读
相关标签
  

闽ICP备14008679号