SpringMVC初始化源码学习

web.xml

<web-app><!--Listener作用:加载并初始化Spring容器(也可以称为父容器)--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/app-context.xml</param-value></context-param><!--加载并初始化DispatcherServlet(同时也加载并且初始化SpringMVC容器,也称为子容器)--><servlet><servlet-name>app</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value></param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>app</servlet-name><url-pattern>/app/*</url-pattern></servlet-mapping><!--一般情况下只需要一个容器即可,不需要存在这种父子容器,当然这需要根据实际业务需求确定-->
</web-app>

ServletContextListener

在 Servlet API 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。

public interface ServletContextListener extends EventListener {//当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。default void contextInitialized(ServletContextEvent sce) {}
//当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。default void contextDestroyed(ServletContextEvent sce) {}
}

先初始化Spring容器

ContextLoaderListener
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {public ContextLoaderListener() {}public ContextLoaderListener(WebApplicationContext context) {super(context);}//Tomcat启动时,会自动调用该方法,初始化Spring容器public void contextInitialized(ServletContextEvent event) {this.initWebApplicationContext(event.getServletContext());}public void contextDestroyed(ServletContextEvent event) {this.closeWebApplicationContext(event.getServletContext());ContextCleanupListener.cleanupAttributes(event.getServletContext());}
}
ContextLoader
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {//当前容器已经存在Spring容器,则抛出异常if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!");} else {servletContext.log("Initializing Spring root WebApplicationContext");Log logger = LogFactory.getLog(ContextLoader.class);if (logger.isInfoEnabled()) {logger.info("Root WebApplicationContext: initialization started");}long startTime = System.currentTimeMillis();try {if (this.context == null) {//创建Spring容器this.context = this.createWebApplicationContext(servletContext);}//如果context是 ConfigurableWebApplicationContext 这种类型if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;if (!cwac.isActive()) {//则设置其父容器if (cwac.getParent() == null) {//这里parent 是nullApplicationContext parent = this.loadParentContext(servletContext);cwac.setParent(parent);}//执行Spring容器初始化,加载并初始化Beanthis.configureAndRefreshWebApplicationContext(cwac, servletContext);}}//将Spring放到ServletContext上下文中,使初始化SpringMVC容器时可以拿到Spring容器并且设置为自己的父容器
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);ClassLoader ccl = Thread.currentThread().getContextClassLoader();if (ccl == ContextLoader.class.getClassLoader()) {currentContext = this.context;} else if (ccl != null) {currentContextPerThread.put(ccl, this.context);}if (logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - startTime;logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");}return this.context;} catch (Error | RuntimeException var8) {logger.error("Context initialization failed", var8);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);throw var8;}}}
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {Class<?> contextClass = this.determineContextClass(sc);if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");} else {//利用反射创建Spring容器,这时Spring容器中属性都还没有值,仅仅是new了一个对象出来而已return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);}}

初始化SpringMVC容器

DispatcherServlet继承关系

Servlet
// Servlet的加载和实例化可以发生在容器启动时,也可以延迟初始化直到有请求需要处理时
public interface Servlet {// 负责初始化Servlet对象,容器创建好Servlet对象后由容器调用调用,只执行一次// 当load-on-startup设置为负数或者不设置时会在Servlet第一次用到时才被调用void init(ServletConfig var1) throws ServletException;// 获取该Servlet的初始化参数信息ServletConfig getServletConfig();// 负责响应客户端的请求,当容器接收到客户端要求访问特定Servlet对象的请求时,会调用该Servlet对象的service()方法,每次请求都会执行void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;// 返回Servlet信息,包含创建者、版本、版权等信息String getServletInfo();// Servlet结束生命周期时调用,释放Servlet对象占用的资源void destroy();
}
GenericServlet
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {}
HttpServlet
public abstract class HttpServlet extends GenericServlet {}

HttpServletBean

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {public final void init() throws ServletException {// 将init-param映射到bean属性  将<init-param>配置参数自动转换成BeanWrapperPropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties);if (!pvs.isEmpty()) {try {BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);ResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext());bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment()));this.initBeanWrapper(bw);bw.setPropertyValues(pvs, true);} catch (BeansException var4) {if (this.logger.isErrorEnabled()) {this.logger.error("Failed to set bean properties on servlet '" + this.getServletName() + "'", var4);}throw var4;}}this.initServletBean();}
}
FrameworkServlet
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {protected final void initServletBean() throws ServletException {this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " '" + this.getServletName() + "'");if (this.logger.isInfoEnabled()) {this.logger.info("Initializing Servlet '" + this.getServletName() + "'");}long startTime = System.currentTimeMillis();try {//初始化SpringMVC容器this.webApplicationContext = this.initWebApplicationContext();this.initFrameworkServlet();} catch (RuntimeException | ServletException var4) {this.logger.error("Context initialization failed", var4);throw var4;}if (this.logger.isDebugEnabled()) {String value = this.enableLoggingRequestDetails ? "shown which may lead to unsafe logging of potentially sensitive data" : "masked to prevent unsafe logging of potentially sensitive data";this.logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails + "': request parameters and headers will be " + value);}if (this.logger.isInfoEnabled()) {this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");}}
}
protected WebApplicationContext initWebApplicationContext() {//从Servlet上下文中获取Spring容器WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());WebApplicationContext wac = null;//SpringMVC容器不为nullif (this.webApplicationContext != null) {wac = this.webApplicationContext;if (wac instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;if (!cwac.isActive()) {//则设置父容器if (cwac.getParent() == null) {cwac.setParent(rootContext);}//加载并初始化SpringMVC中的Beanthis.configureAndRefreshWebApplicationContext(cwac);}}}//根据ContextAttribute找SpringMVC容器if (wac == null) {wac = this.findWebApplicationContext();}//如果没有找到,则创建SpringMVC容器if (wac == null) {wac = this.createWebApplicationContext(rootContext);}//加载并初始化SpringMVC中的Beanif (!this.refreshEventReceived) {synchronized(this.onRefreshMonitor) {//初始化DispatcherServlet及九大组件this.onRefresh(wac);}}if (this.publishContext) {String attrName = this.getServletContextAttributeName();//将SpringMVC容器放入到Servlet上下文中this.getServletContext().setAttribute(attrName, wac);}return wac;}
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {Class<?> contextClass = this.getContextClass();if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");} else {//获取利用反射获取SringMVC容器ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);//设置系统环境变量wac.setEnvironment(this.getEnvironment());//设置父容器wac.setParent(parent);//获取web.xml配置的 contextConfigLocationString configLocation = this.getContextConfigLocation();if (configLocation != null) {wac.setConfigLocation(configLocation);}//加载初始化Beanthis.configureAndRefreshWebApplicationContext(wac);return wac;}}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {//设置SpringMVC容器id    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {if (this.contextId != null) {wac.setId(this.contextId);} else {wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(this.getServletContext().getContextPath()) + '/' + this.getServletName());}}
//设置Servlet上下文wac.setServletContext(this.getServletContext());//设置Serlvet一些配置参数wac.setServletConfig(this.getServletConfig());//设置namespacewac.setNamespace(this.getNamespace());//设置ContextRefreshListenerwac.addApplicationListener(new SourceFilteringListener(wac, new FrameworkServlet.ContextRefreshListener()));//获取Environment并调用initPropertySources替换servletContextInitParams和servletConfigInitParams参数ConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment)env).initPropertySources(this.getServletContext(), this.getServletConfig());}
//暂无实现this.postProcessWebApplicationContext(wac);this.applyInitializers(wac);wac.refresh();}
DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {protected void onRefresh(ApplicationContext context) {this.initStrategies(context);}
}
protected void initStrategies(ApplicationContext context) {//初始化上传文件解析器this.initMultipartResolver(context);//初始化国际化相关解析器this.initLocaleResolver(context);//初始化主题解析器this.initThemeResolver(context);//初始化处理器映射器this.initHandlerMappings(context);//初始化处理器适配器this.initHandlerAdapters(context);//初始化处理器异常解析器this.initHandlerExceptionResolvers(context);this.initRequestToViewNameTranslator(context);//初始化视图解析器this.initViewResolvers(context);this.initFlashMapManager(context);
}
private void initLocaleResolver(ApplicationContext context) {try {//从Spring容器中获取LocaleResolver的实现类this.localeResolver = (LocaleResolver)context.getBean("localeResolver", LocaleResolver.class);if (this.logger.isTraceEnabled()) {this.logger.trace("Detected " + this.localeResolver);} else if (this.logger.isDebugEnabled()) {this.logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());}} catch (NoSuchBeanDefinitionException var3) {this.localeResolver = (LocaleResolver)this.getDefaultStrategy(context, LocaleResolver.class);if (this.logger.isTraceEnabled()) {this.logger.trace("No LocaleResolver 'localeResolver': using default [" + this.localeResolver.getClass().getSimpleName() + "]");}}}
 private void initThemeResolver(ApplicationContext context) {try {//从Spring容器中获取ThemeResolver的实现类this.themeResolver = (ThemeResolver)context.getBean("themeResolver", ThemeResolver.class);if (this.logger.isTraceEnabled()) {this.logger.trace("Detected " + this.themeResolver);} else if (this.logger.isDebugEnabled()) {this.logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());}} catch (NoSuchBeanDefinitionException var3) {this.themeResolver = (ThemeResolver)this.getDefaultStrategy(context, ThemeResolver.class);if (this.logger.isTraceEnabled()) {this.logger.trace("No ThemeResolver 'themeResolver': using default [" + this.themeResolver.getClass().getSimpleName() + "]");}}}
private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;
//如果detectAllHandlerMappings为true 则从Spring容器中获取所有实现HandlerMapping接口的实现类if (this.detectAllHandlerMappings) {// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<>(matchingBeans.values());//并且根据@Order注解 进行排序AnnotationAwareOrderComparator.sort(this.handlerMappings);}}else {try {//否则从Spring容器中获取beanName为"handlerMapping"的实现类HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);//并且赋值给handlerMappingsthis.handlerMappings = Collections.singletonList(hm);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later.}}
//如果handlerMappings还是nullif (this.handlerMappings == null) {//则获取默认配置文件配置的HandlerMapping(DispatcherServlet.properties)this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerMappings declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}
//遍历所有的HandlerMappingsfor (HandlerMapping mapping : this.handlerMappings) {if (mapping.usesPathPatterns()) {//如果mapping 是自动使用路径匹配//则parseRequestPatch设置为truethis.parseRequestPath = true;break;}}}
private void initHandlerAdapters(ApplicationContext context) {this.handlerAdapters = null;
//如果detectAllHandlerAdapters=trueif (this.detectAllHandlerAdapters) {//则从Spring容器中获取所有实现HandlerAdapter接口的实现类Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerAdapters = new ArrayList<>(matchingBeans.values());// 并且根据@Order注解进行排序AnnotationAwareOrderComparator.sort(this.handlerAdapters);}}else {try {//如果detectAllHandlerAdapters=false,则获取beanName为"handlerAdpater"的handlerApater实现类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.}}//如果handlerApaters==null  则从获取默认配置文件中配置的实现类if (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}
private void initHandlerExceptionResolvers(ApplicationContext context) {this.handlerExceptionResolvers = null;
//如果detectAllHandlerExceptionResolvers=true 则从Spring容器中获取所有实现HandlerExeptionResolver接口的实现类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());// 根据@Order进行排序AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);}}else {try {//如果detectAllHandlerExceptionResolvers=false 则从spring容器中获取beanName是"handlerExceptionResolver"的实现类HandlerExceptionResolver her =context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);this.handlerExceptionResolvers = Collections.singletonList(her);}catch (NoSuchBeanDefinitionException ex) {// Ignore, no HandlerExceptionResolver is fine too.}}// 如果handlerExceptionResolvers==null 则获取默认配置文件中默认的实现类if (this.handlerExceptionResolvers == null) {this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}
private void initRequestToViewNameTranslator(ApplicationContext context) {try {//从Spring容器中获取beanName是"viewNameTranslator"的实现类this.viewNameTranslator =context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);if (logger.isTraceEnabled()) {logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.viewNameTranslator);}}catch (NoSuchBeanDefinitionException ex) {// 如果抛出异常 则获取默认配置文件中配置的实现类this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);if (logger.isTraceEnabled()) {logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");}}}
private void initViewResolvers(ApplicationContext context) {this.viewResolvers = null;
//如果detectAllViewResolvers=true 则从Spring容器获取ViewResolver的实现类if (this.detectAllViewResolvers) {// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.Map<String, ViewResolver> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);if (!matchingBeans.isEmpty()) {this.viewResolvers = new ArrayList<>(matchingBeans.values());// 然后根据@Order进行排序AnnotationAwareOrderComparator.sort(this.viewResolvers);}}else {try {//如果detectAllViewResolvers=false 则从Spring容器获取beanName是"viewResolver"的实现类ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);this.viewResolvers = Collections.singletonList(vr);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default ViewResolver later.}}// 如果viewResolvers==null 则获取配置文件中指定默认的ViewResolver实现类if (this.viewResolvers == null) {this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);if (logger.isTraceEnabled()) {logger.trace("No ViewResolvers declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}
private void initFlashMapManager(ApplicationContext context) {try {//从Spring容器中获取beanName是"flashMapManager"的实现类this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);if (logger.isTraceEnabled()) {logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.flashMapManager);}}catch (NoSuchBeanDefinitionException ex) {// 异常 则从配置文件中获取默认的实现类this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);if (logger.isTraceEnabled()) {logger.trace("No FlashMapManager '" + FLASH_MAP_MANAGER_BEAN_NAME +"': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");}}}
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {//defaultStrategies为空 则还没有加载过DispatcherServlet.properties文件if (defaultStrategies == null) {try {//根据DispatcherServlet.properties 根据ClassPatchRsourceClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);//将properties文件内容加载到defaultStrategies中defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);}catch (IOException ex) {throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());}}
//根据传入的参数name 作为keyString key = strategyInterface.getName();//从defaultStrategies(配置文件)中查找String value = defaultStrategies.getProperty(key);if (value != null) {//找到 则根据,进行分割,转化为数组String[] classNames = StringUtils.commaDelimitedListToStringArray(value);List<T> strategies = new ArrayList<>(classNames.length);for (String className : classNames) {try {//遍历数组 通过ClassUtils.forName 构建ClassClass<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());//根据class 创建BeanObject strategy = createDefaultStrategy(context, clazz);//添加到strategies集合中strategies.add((T) strategy);}catch (ClassNotFoundException ex) {throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className +"] for interface [" + key + "]", ex);}catch (LinkageError err) {throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" +className + "] for interface [" + key + "]", err);}}//并返回该集合return strategies;}else {return Collections.emptyList();}}

DispatcherServlet.properties


org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\org.springframework.web.servlet.function.support.RouterFunctionMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\org.springframework.web.servlet.function.support.HandlerFunctionAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/650744.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么 FPGA 比 CPU 和 GPU 快?

FPGA、GPU 与 CPU——AI 应用的硬件选择 现场可编程门阵列 (FPGA) 为人工智能 (AI) 应用带来许多优势。图形处理单元 (GPU) 和传统中央处理单元 (CPU) 相比如何&#xff1f; 人工智能&#xff08;AI&#xff09;一词是指能够以类似于人类的方式做出决策的非人类机器智能。这包…

k8s 进阶实战笔记 | Pod 创建过程详解

Pod 创建过程详解 ​ 初始状态0 controller-manager、scheduler、kubelet组件通过 list-watch 机制与 api-server 通信并检查资源变化 第一步 用户通过 CLI 或者 WEB 端等方式向 api-server 发送创建资源的请求&#xff08;比如&#xff1a;我要创建一个replicaset资源&…

设计一套扑克牌

约束和假设 这是一幅用于类似扑克和二十一点等游戏的通用扑克牌吗&#xff1f; 我们可以假设这副牌有52张&#xff08;2-10&#xff0c;杰克&#xff0c;女王&#xff0c;国王&#xff0c;埃斯&#xff09;和4种花色吗&#xff1f; 我们可以假设输入是有效的&#xff0c;还是需…

多表查询练习题

student表: score表: 向student表插入记录: 向score表插入记录: 1.查询student表的所有记录 SELECT * FROM student;2.查询student表的第2条到4条记录 SELECT * FROM student LIMIT 1,3;3.从student表查询所有学生的学号&#xff08;id&#xff09;、姓名&#xff08;name&…

【复现】Laykefu客服系统后台漏洞合集_29

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 2. 漏洞二&#xff1a; 3. 漏洞三&#xff1a; 4. 漏洞四&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 Laykefu客服系统是thinkphp5Gatewayworker搭建的web客服…

【Linux】:线程安全的单例模式

线程安全的单例模式 一.STL和智能指针的安全二.单例模式1.基本概念2.懒汉和饿汉的实现方式 三.常见的其它锁四.读者写者模型 一.STL和智能指针的安全 1.STL中的容器是否是线程安全的? 不是. 原因是, STL 的设计初衷是将性能挖掘到极致, 而一旦涉及到加锁保证线程安全, 会对性…

router4j--SpringCloud动态路由利器

前言 本文介绍Java的动态路由中间件&#xff1a;router4j。router4j用于SpringCloud项目&#xff0c;它可以将某个url请求路由到指定的机器上&#xff0c;也可以将所有请求强制转到指定机器。 问题描述 Java后端在开发SpringCloud项目时如果同一个应用起了多个实例&#xff…

【K12】tk窗口+plt图像功能-学习物理中的串并联研究【附源码说明】

程序源码 import tkinter as tk import matplotlib.pyplot as plt# 初始化 matplotlib 的字体设置 plt.rcParams[font.family] SimHei# 计算串联电路的函数 def calculate_series():try:# 获取用户输入的电阻值并转换为浮点数r1 float(entry_r1.get())r2 float(entry_r2.ge…

第二篇:数据结构与算法-链表

概念 链表是线性表的链式存储方式&#xff0c;逻辑上相邻的数据在计算机内的存储位置不必须相邻&#xff0c; 可以给每个元素附加一个指针域&#xff0c;指向下一个元素的存储位 置。 每个结点包含两个域&#xff1a;数据域和指针域&#xff0c;指针域存储下一个结点的地址&…

C/C++ 跨文件共享全局变量

目录 效果 项目 代码 下载 为了实现跨文件共享全局变量&#xff0c;我们可以使用 extern 关键字。extern 关键字用于声明一个变量&#xff0c;该变量在其他地方已经定义。它告诉编译器这个变量在其他文件中已经定义了&#xff0c;不需要重新分配内存空间&#xff0c;只需要…

C语言-指针的基本知识(上)

一、关于内存 存储器&#xff1a;存储数据器件 外存 外存又叫外部存储器&#xff0c;长期存放数据&#xff0c;掉电不丢失数据 常见的外存设备&#xff1a;硬盘、flash、rom、u盘、光盘、磁带 内存 内存又叫内部存储器&#xff0c;暂时存放数据&#xff0c;掉电数据…

蓝桥杯-sort排序(上)

sort排序 &#x1f388;1.算法说明&#x1f388;2.例题&#x1f52d;2.1例题一&#x1f52d;2.2例题二&#x1f52d;2.3例题三&#x1f52d;2.4例题四&#x1f52d;2.5例题五&#x1f52d;2.6例题六 &#x1f388;1.算法说明 &#x1f50e;对于一个数组&#xff0c;通过对数组中…

Spring Security 存储密码之 JDBC

Spring Security的JdbcDaoImpl实现了UserDetailsService接口,通过使用JDBC提供支持基于用户名和密码的身份验证。 JdbcUserDetailsManager扩展了JdbcDaoImpl,通过UserDetailsManager接口提供UserDetails的管理功能。 当Spring Security配置为接受用户名/密码进行身份验证时,…

南卡Neo2评测:实力诠释骨传导耳机全能旗舰,细节展现匠心之作

前段时间朋友让我帮他寻找一款佩戴舒适、音质体验好的蓝牙耳机&#xff0c;因为比较忙所以一直把这件事搁置了&#xff0c;刚好这两天比较闲&#xff0c;所以也是在综合个人的经验和目前较为热门的一些品牌款式&#xff0c;决定帮他寻找一款骨传导耳机&#xff0c;因为骨传导耳…

JVM-字节码应用

一、字节码的应用远超你的想象 二、ASM介绍与读取字节码实战 用CoreAPI解析和TreeAPI都能做字节码解析&#xff0c;区别&#xff0c;TreeAPI必须读取完整字节码信息&#xff0c;才能做解析。 下面代码&#xff0c;使用CoreAPI做解析&#xff1a; package asm;public class MyM…

grep查找过滤

如果你想使用 ps aux | grep corp 来过滤进程&#xff0c;并且希望不包含包含 “vscode” 路径的进程&#xff0c;你可以使用 grep -v 来排除包含特定字符串的行。下面是一个示例&#xff1a; ps aux | grep corp | grep -v "vscode"这个命令首先使用 ps aux | grep…

[已解决]504 Gateway Time-out 网关超时

文章目录 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时思路解决 问题&#xff1a;504 Gateway Time-out 504 Gateway Time-out 网关超时 思路 网上的常规思路是修改nginx配置文件,增加请求执行时间,试过没有用 keepalive_timeout 600; fastcgi_con…

JVM系列-7内存调优

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring原理、JUC原理、Kafka原理、分布式技术原理、数据库技术、JVM原理&#x1f525;如果感觉博主的文…

案例分享 | 助力数字化转型:嘉为科技项目管理平台上线

嘉为科技项目管理平台&#xff08;一期&#xff09;基于易趋&#xff08;EasyTrack&#xff09;进行实施&#xff0c;通过近一年的开发及试运行&#xff0c;现已成功交付上线、推广使用&#xff0c;取得了良好的应用效果。 1.关于广州嘉为科技有限公司&#xff08;以下简称嘉为…

龙芯,启动!

本文为小白从购买龙芯3A6000主板、硬件安装、软件安装的简单教程。 1 购买 目前&#xff08;2024年1月&#xff09;最新的龙芯主板采用龙芯处理器3A6000和7A2000桥片设计的DTX主板&#xff0c;CPU主频可达2.5GHz&#xff0c;2个DDR4内存插槽。桥片内部集成GPU&#xff0c;支…