使用Spring MVC搭建了web项目(~/IdeaProjects/Beautiful1205/test-springmvc/springmvctest,有时间上传至github)后,我们来探索一下原理...

一、Spring MVC 与 Spring Boot

Spring MVC提供了一种轻度耦合的方式来开发web应用。它是Spring的一个模块,是一个web框架。通过DispatcherServlet, ModelAndView 和 ViewResolver,开发web应用变得很容易。(实际上还有很多其他的web框架,同样可以跟Spring进行整合。这就要求Spring有一些通用的配置,不但能支持Spring MVC也能支持Structs等其他web框架。这里看下官网吧)

Spring Boot实现了自动配置,降低了项目搭建的复杂度。它主要是为了解决使用Spring框架需要进行大量的配置太麻烦的问题,所以它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box)。

在SpringBoot项目中整合Spring MVC只需要添加对应的starer依赖即可。

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

SpringBoot、SpringMVC和Spring区别_努力的土豆的博客-CSDN博客_springboot springmvc

SpringBoot、SpringMVC整合与比较:_kingmax54212008的博客-CSDN博客

二、Spring MVC原理

http://www.it165.net/pro/html/201604/66385.html

2.1、从Web应用角度看Spring MVC

在Servlet模型中,请求-响应的实现依赖于两大元素的共同配合:

  1. 在web.xml中配置Servlet及其映射关系
  2. 在Servlet实现类中完成响应逻辑

项目规模扩大之后,请求-响应的映射关系全部定义在web.xml中,将造成web.xml的不断膨胀而变得难以维护。针对这个问题,SpringMVC提出的方案就是:提炼一个核心的Servlet覆盖对所有Http请求的处理。这一被提炼出来的Servlet,通常被我们称之为:核心分发器。在SpringMVC中,核心分发器就是org.springframework.web.servlet.DispatcherServlet

核心分发器要解决的是下面两个问题:

  • 问题1:核心Servlet应该能够建立起一整套完整的对所有Http请求进行规范化处理的流程。
  • 问题2:核心Servlet应该能够根据一定的规则对不同的Http请求分发到不同的Servlet对象上去进行处理。

针对上面的这个两个问题,SpringMVC的解决方案是:将整个处理流程规范化,并把每一个处理步骤分派到不同的组件中进行处理

  • 处理流程规范化 :将处理流程划分为若干个步骤(任务),并使用一条明确的逻辑主线将所有的步骤串联起来
  • 处理流程组件化 : 将处理流程中的每一个步骤(任务)都定义为接口,并为每个接口赋予不同的实现模式

处理流程规范化的首要内容就是考虑一个通用的Servlet响应程序大致应该包含的逻辑步骤:对Http请求进行初步处理 -> 查找与之对应的Controller处理类(方法) -> 调用相应的Controller处理类(方法) -> 完成业务逻辑 -> 对Controller处理类(方法)调用时可能发生的异常进行处理 -> 根据Controller处理类(方法)的调用结果进行Http响应处理。

所谓的组件化,实际上也就是使用编程语言将这些逻辑语义表达出来。在Java语言中,最适合表达逻辑处理语义的语法结构是接口,而接口可以有不同的实现,因此上述的四个流程也就被定义为了四个不同接口,它们分别是:HandlerMapping、HandlerAdapter、HandlerExceptionResolver、ViewResolver

2.2、从Spring角度看Spring MVC

从上面可以看出,组件是核心分发器(DispatchServlet)的核心所在,它们是http请求处理的逻辑载体,DispatcherServlet是逻辑处理的调度中心,组件则是被调度的操作对象。

Spring容器在这里所起到的作用协助DispatcherServlet更好地对组件进行管理

我们知道,SpringMVC的组件是一个个的接口定义,当我们在SpringMVC的核心配置文件中定义一个组件时,使用的却是组件的实现类。

用具体的实现类来指定组件的行为模式,不同的实现类代表了不同的行为模式,它们在Spring中是可以共存的。

Spring容器对这些实现类进行管理,具体如何使用,由应用程序本身来决定。

上图是Spring官方reference中的一幅图,DispatchServlet对外接收http的请求,而请求的处理是依靠组件来完成的。

组件的接口实现的是依靠Spring IOC容器(WebApplicationContext)来管理的。

从这个图中我们可以看出,Spring MVC实现web应用是依赖于Spring提供的基础特性(IOC等)的。(图中的两个WebApplicationContext的父子关系)

三、上下文初始化过程

3.1、Spring MVC 入口配置文件web.xml

遵循servlet规范,Spring MVC的web应用的入口配置文件也是web.xml。在web.xml配置文件中,有两个主要的配置:ContextLoaderListenerDispatcherServlet。同样的关于spring配置文件的相关配置也有两部分:context-param和DispatcherServlet中的init-param。

在ContextLoaderListener中创建的Spring容器主要用于整个Web应用程序需要共享的一些组件,比如DAO、数据库的ConnectionFactory等;而由DispatcherServlet创建的Spring MVC的容器主要用于和该Servlet相关的一些组件,比如Controller、ViewResovler等。在实际工程中,一个项目中会包括很多配置,根据不同的业务模块来划分,我们一般思路是:Spring根容器负责所有其他非controller的Bean的注册,而SpringMVC只负责controller相关的Bean的注册。参考链接。

参考链接

Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext,使得拥有web功能。

先看一下WebApplicationContext是如何扩展ApplicationContext来添加对Web环境的支持的。WebApplicationContext接口定义如下:

package org.springframework.web.context;import javax.servlet.ServletContext;import org.springframework.context.ApplicationContext;
import org.springframework.lang.Nullable;/*** Interface to provide configuration for a web application. This is read-only while* the application is running, but may be reloaded if the implementation supports this.** <p>This interface adds a {@code getServletContext()} method to the generic* ApplicationContext interface, and defines a well-known application attribute name* that the root context must be bound to in the bootstrap process.** <p>Like generic application contexts, web application contexts are hierarchical.* There is a single root context per application, while each servlet in the application* (including a dispatcher servlet in the MVC framework) has its own child context.** <p>In addition to standard application context lifecycle capabilities,* WebApplicationContext implementations need to detect {@link ServletContextAware}* beans and invoke the {@code setServletContext} method accordingly.** @author Rod Johnson* @author Juergen Hoeller* @since January 19, 2001* @see ServletContextAware#setServletContext*/
public interface WebApplicationContext extends ApplicationContext {/*** Context attribute to bind root WebApplicationContext to on successful startup.* <p>Note: If the startup of the root context fails, this attribute can contain* an exception or error as value. Use WebApplicationContextUtils for convenient* lookup of the root WebApplicationContext.* @see org.springframework.web.context.support.WebApplicationContextUtils#getWebApplicationContext* @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext*/String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";/*** Scope identifier for request scope: "request".* Supported in addition to the standard scopes "singleton" and "prototype".*/String SCOPE_REQUEST = "request";/*** Scope identifier for session scope: "session".* Supported in addition to the standard scopes "singleton" and "prototype".*/String SCOPE_SESSION = "session";/*** Scope identifier for the global web application scope: "application".* Supported in addition to the standard scopes "singleton" and "prototype".*/String SCOPE_APPLICATION = "application";/*** Name of the ServletContext environment bean in the factory.* @see javax.servlet.ServletContext*/String SERVLET_CONTEXT_BEAN_NAME = "servletContext";/*** Name of the ServletContext init-params environment bean in the factory.* <p>Note: Possibly merged with ServletConfig parameters.* ServletConfig parameters override ServletContext parameters of the same name.* @see javax.servlet.ServletContext#getInitParameterNames()* @see javax.servlet.ServletContext#getInitParameter(String)* @see javax.servlet.ServletConfig#getInitParameterNames()* @see javax.servlet.ServletConfig#getInitParameter(String)*/String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";/*** Name of the ServletContext attributes environment bean in the factory.* @see javax.servlet.ServletContext#getAttributeNames()* @see javax.servlet.ServletContext#getAttribute(String)*/String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";/*** Return the standard Servlet API ServletContext for this application.*/@NullableServletContext getServletContext();}
* <p>Like generic application contexts, web application contexts are hierarchical.
* There is a single root context per application, while each servlet in the application
* (including a dispatcher servlet in the MVC framework) has its own child context.

注释翻译过来就是:Web环境中的每个应用都有一个根上下文,同时每个servlet还都持有一个子上下文

ContextLoaderListener:spring-web-5.1.10.RELEASE.jar!/org/springframework/web/context/ContextLoaderListener.class

DispatcherServlet

(/Users/-/.m2/repository/org/springframework/boot/spring-boot/2.1.9.RELEASE/spring-boot-2.1.9.RELEASE.jar!/org/springframework/boot/web/servlet/context/ServletWebServerApplicationContext.class prepareWebApplicationContext() 方法)

3.2、Spring容器(根上下文)的初始化

Web环境中的每个应用都有一个根上下文,同时每个servlet还都持有一个子上下文。对于这样的Context结构在Spring MVC中是如何实现的呢?下面就先从ROOT Context入手,ROOT Context是在ContextLoaderListener中配置的,ContextLoaderListener读取context-param中的contextConfigLocation指定的配置文件,创建ROOT Context。下面看一下ContextLoaderListener中创建context的源码:(注意看注释第一句话)

package org.springframework.web.context;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;/*** Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.* Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.** <p>As of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web* application context via the {@link #ContextLoaderListener(WebApplicationContext)}* constructor, allowing for programmatic configuration in Servlet 3.0+ environments.* See {@link org.springframework.web.WebApplicationInitializer} for usage examples.** @author Juergen Hoeller* @author Chris Beams* @since 17.02.2003* @see #setContextInitializers* @see org.springframework.web.WebApplicationInitializer*/
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {.../*** Initialize the root web application context.*/@Overridepublic void contextInitialized(ServletContextEvent event) {initWebApplicationContext(event.getServletContext());}...}
package org.springframework.web.context;import *****;/*** Performs the actual initialization work for the root application context.* Called by {@link ContextLoaderListener}.** <p>Looks for a {@link #CONTEXT_CLASS_PARAM "contextClass"} parameter at the* {@code web.xml} context-param level to specify the context class type, falling* back to {@link org.springframework.web.context.support.XmlWebApplicationContext}* if not found. With the default ContextLoader implementation, any context class* specified needs to implement the {@link ConfigurableWebApplicationContext} interface.** <p>Processes a {@link #CONFIG_LOCATION_PARAM "contextConfigLocation"} context-param* and passes its value to the context instance, parsing it into potentially multiple* file paths which can be separated by any number of commas and spaces, e.g.* "WEB-INF/applicationContext1.xml, WEB-INF/applicationContext2.xml".* Ant-style path patterns are supported as well, e.g.* "WEB-INF/*Context.xml,WEB-INF/spring*.xml" or "WEB-INF/**/*Context.xml".* If not explicitly specified, the context implementation is supposed to use a* default location (with XmlWebApplicationContext: "/WEB-INF/applicationContext.xml").** <p>Note: In case of multiple config locations, later bean definitions will* override ones defined in previously loaded files, at least when using one of* Spring's default ApplicationContext implementations. This can be leveraged* to deliberately override certain bean definitions via an extra XML file.** <p>Above and beyond loading the root application context, this class can optionally* load or obtain and hook up a shared parent context to the root application context.* See the {@link #loadParentContext(ServletContext)} method for more information.** <p>As of Spring 3.1, {@code ContextLoader} supports injecting the root web* application context via the {@link #ContextLoader(WebApplicationContext)}* constructor, allowing for programmatic configuration in Servlet 3.0+ environments.* See {@link org.springframework.web.WebApplicationInitializer} for usage examples.** @author Juergen Hoeller* @author Colin Sampaleanu* @author Sam Brannen* @since 17.02.2003* @see ContextLoaderListener* @see ConfigurableWebApplicationContext* @see org.springframework.web.context.support.XmlWebApplicationContext*/
public class ContextLoader {}

/spring-web-5.2.5.RELEASE.jar!/org/springframework/web/context/ContextLoader.class类中initWebApplicationContext()方法如下:

 /*** Initialize Spring's web application context for the given servlet context,* using the application context provided at construction time, or creating a new one* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.* @param servletContext current servlet context* @return the new WebApplicationContext* @see #ContextLoader(WebApplicationContext)* @see #CONTEXT_CLASS_PARAM* @see #CONFIG_LOCATION_PARAM*/public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {//在整个web应用中,只能有一个根上下文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!");}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 {// Store context in local instance variable, to guarantee that it is available on ServletContext shutdown.if (this.context == null) {// 在这里执行了创建WebApplicationContext的操作this.context = createWebApplicationContext(servletContext);}if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;if (!cwac.isActive()) {// The context has not yet been refreshed -> provide services such as// setting the parent context, setting the application context id, etcif (cwac.getParent() == null) {// The context instance was injected without an explicit parent ->// determine parent for root web application context, if any.ApplicationContext parent = loadParentContext(servletContext);cwac.setParent(parent);}configureAndRefreshWebApplicationContext(cwac, servletContext);}}//将根上下文放置在servletContext中       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 (RuntimeException | Error ex) {logger.error("Context initialization failed", ex);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);throw ex;}}

再看一下WebApplicationContext对象是如何创建的:

 /*** Instantiate the root WebApplicationContext for this loader, either the* default context class or a custom context class if specified.* <p>This implementation expects custom contexts to implement the* {@link ConfigurableWebApplicationContext} interface.* Can be overridden in subclasses.* <p>In addition, {@link #customizeContext} gets called prior to refreshing the* context, allowing subclasses to perform custom modifications to the context.* @param sc current servlet context* @return the root WebApplicationContext* @see ConfigurableWebApplicationContext*/protected WebApplicationContext createWebApplicationContext(ServletContext sc) {Class<?> contextClass = determineContextClass(sc);if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() +"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");}return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);}

以上是web容器中根上下文的加载与初始化,下面介绍一下Spring MVC对应的上下文是如何加载的。

3.3、Spring MVC容器(子上下文)的初始化

以上是web容器中根上下文的加载与初始化,在完成对ContextLoaderListener的初始化以后,web容器开始初始化DispatchServlet,DispatchServlet会建立自己的上下文来管理Spring MVC的bean对象。在建立这个自己持有的上下文的时候,会从ServletContext中得到根上下文作为DispatchServlet持有的上下文的双亲上下文,再对自己持有的上下文进行初始化,最后把自己持有的这个上下文也保存到ServletContext中。

我们先看下DispatchServlet的继承关系,如下图,

DispatchServlet通过继承FrameworkServlet和HttpServletBean而继承了HttpServlet。HttpServletBean是Spring对于Servlet最低层次的抽象。

在这一层抽象中,Spring会将这个Servlet视作是一个Spring的bean,并将web入口配置文件web.xml中DispatchServlet定义的init-param参数中的值作为bean的属性注入进来。

DispatcherServlet也是一个Servlet,根据Servlet规范的定义,其中有两大核心方法:init()方法service()方法。

  • init()方法:在整个系统启动时运行,且只运行一次。主要的调用顺序是GenericServlet#init() --> HttpServletBean#init() -->FrameworkServlet#initServletBean() --> FrameworkServlet#initWebApplicationContext()。在init方法中我们往往会对整个应用程序进行初始化操作。这些初始化操作包括对容器(WebApplicationContext)的初始化、组件和外部资源的初始化等等。
  • service()方法:在整个系统运行的过程中处于侦听模式,侦听并处理所有的Web请求。因此,在service及其相关方法中,我们看到的则是对Http请求的处理流程。

DispatchServlet、FrameworkServlet和HttpServletBean之间的调用关系如下,首先是HttpServletBean,其次是FrameworkServlet,最后是DispatchServlet。FrameworkServlet是在HttpServletBean的基础之上的进一步抽象。通过FrameworkServlet真正初始化了一个Spring的容器(WebApplicationContext),并引入到ServletContext之中(注意这个子上下文放到ServletContext时的key和根上下文是不一样的)。在这个调用关系中,可以看到MVC的初始化是再DispatchServlet的initStrategies方法中完成的,包括对各种MVC框架的实现元素,比如支持国际化的LocaleResolver、支持request映射的HandlerMappings、以及视图生成的ViewResolver等的初始化。

看下FrameworkServlet#initServletBean()的实现,

 /*** Overridden method of {@link HttpServletBean}, invoked after any bean properties* have been set. Creates this servlet's WebApplicationContext.*/@Overrideprotected final void initServletBean() throws ServletException {getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");if (logger.isInfoEnabled()) {logger.info("Initializing Servlet '" + getServletName() + "'");}long startTime = System.currentTimeMillis();try {this.webApplicationContext = initWebApplicationContext();initFrameworkServlet();}catch (ServletException | RuntimeException ex) {logger.error("Context initialization failed", ex);throw ex;}if (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";logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +"': request parameters and headers will be " + value);}if (logger.isInfoEnabled()) {logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");}}

其中,FrameworkServlet#initWebApplicationContext的实现

 /*** Initialize and publish the WebApplicationContext for this servlet.* <p>Delegates to {@link #createWebApplicationContext} for actual creation* of the context. Can be overridden in subclasses.* @return the WebApplicationContext instance* @see #FrameworkServlet(WebApplicationContext)* @see #setContextClass* @see #setContextConfigLocation*/protected WebApplicationContext initWebApplicationContext() {//从ServletContext中取得根上下文WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null;if (this.webApplicationContext != null) {// A context instance was injected at construction time -> use it//如果在构造时已经注入了context则直接使用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, etcif (cwac.getParent() == null) {// The context instance was injected without an explicit parent -> set// the root application context (if any; may be null) as the parentcwac.setParent(rootContext);}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 idwac = findWebApplicationContext();}if (wac == null) {// No context instance is defined for this servlet -> create a local one//创建Spring MVC的上下文,并将根上下文作为起双亲上下文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.synchronized (this.onRefreshMonitor) {//会最终DispatchServlet的initStrategies()方法, 进行MVC的初始化onRefresh(wac);}}if (this.publishContext) {// Publish the context as a servlet context attribute.// 名字前缀是   public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT.";String attrName = getServletContextAttributeName();getServletContext().setAttribute(attrName, wac);}return wac;}

通过initWebApplicationContext方法的调用,创建了DispatcherServlet对应的context,并将其放置到ServletContext中,这样就完成了在web容器中构建Spring MVC容器的过程。

四、Spring MVC 上下初始化流程图

ServletContext是Spring容器的宿主环境,Spring容器又包含整个应用的根上下文和每个servlet的子上下文。

用到的组件:(https://blog.csdn.net/lu930124/article/details/51586031)

组件 作用
前端控制器 接收请求 响应结果  相当于转发器
处理器映射器 根据请求的url查找handler
处理器适配器 按照特定规则去执行handler 注意:在开发handler时按照handleradapter的要求去做,这样适配器才可以去执行handler
视图解析器 进行视图解析,根据逻辑视图名解析成真正的视图
视图 是一个接口,实现类支持不同的view类型(jsp freemarker, pdf……)
处理器handler  编写handler时按照handleradapter的要求去做,这样适配器才可以去正确执行handler

Spring Web项目相关推荐

  1. 普通的Spring Web项目正常启动,在访问某些JSP页面时,页面会报错 http://java.sun.com/jsp/jstl/core

    问题描述:普通的Spring Web项目正常启动,但是在访问某些JSP页面时,页面会报错出现:org.apache.jasper.JasperException: The absolute uri: ...

  2. Maven+Spring Web 项目结构在Eclipse下面的实现

    软件151  马清友 我们在这里所要实现的关键就是如何保证 Maven 规定的目录结构. 这里对于Maven的目录结构做一个简单的说明:  src/main /Java src/main/resour ...

  3. 03)java spi应用 java spring web项目 去除web.xml

    上一节 学习完了 原始 java web项目 无web.xml怎么配置servlet 这节学习 java web项目 无web.xml怎么集成spring框架 使用过web.xml集成spring框架 ...

  4. Spring web项目中web.xml常用的配置

    设置请求和响应时的编码为UTF-8 <filter><filter-name>encodingFilter</filter-name><filter-clas ...

  5. idea下,Jetty采用main方法启动web项目

    为什么80%的码农都做不了架构师?>>>    对于maven多模块的spring web项目,本地开发时,启动的方式一般有如下几种: 使用容器(tomcat/jetty/resin ...

  6. spring之:XmlWebApplicationContext作为Spring Web应用的IoC容器,实例化和加载Bean的过程...

    它既是 DispatcherServlet 的 (WebApplicationContext)默认策略,又是 ContextLoaderListener 创建 root WebApplicationC ...

  7. maven mybatis mysql_Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问...

    标签: 本篇内容还是建立在上一篇Java Web学习系列--Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Ja ...

  8. spring boot构建基础版web项目(一)springboot、thymeleaf控制层基础构

    原文作者:弥诺R 原文地址:http://www.minuor.com/147852147/article 转载声明:转载请注明原文地址,注意版权维护,谢谢! 写前说明 根据个人在各篇博文中看到的信息 ...

  9. 【问题记录】eclipse启动web项目时,spring会初始化两次

    背景:一个tomcat,一个eclipse,一个SSM框架的web项目.在eclipse中新建tomcat服务器,默认配置,然后在服务器配置中将Server Locations改成Use Tomcat ...

最新文章

  1. Redis-11使用 watch 命令监控事务
  2. 柯洁:这是我最后一次人机大战 且看且珍惜
  3. Batchsize不够大,如何发挥BN性能?探讨神经网络在小Batch下的训练方法
  4. Java架构师在线视频,架构师的7大必备技能
  5. CPU 硬盘性能到底相差多少
  6. ubuntu下面使用stata进行线性回归
  7. 开源飞控爱好者_开源爱好者的10种节日礼物创意
  8. 5319. 删除回文子序列
  9. 构造函数和方法的区别
  10. 【讲座预告】Processing Learner Texts: from Annotation to ...
  11. 全国计算机一级2021选择题,2021年度全国计算机一级考试选择题试题与详细答案.doc...
  12. yyyy-MM-dd 转化成 中国标准时间(Tue Dec 31 2019 00:00:00 GMT+0800 (中国标准时间))
  13. 双十一来临,你就不想知道阿里后台都做了哪些准备吗?
  14. 『Ocelot』.NET开源API网关 – Ocelot详细使用及其说明(可当文档收藏使用)
  15. 绩效管理对 HR 的重要性
  16. 帅气的团队介绍HTML源码
  17. 枯燥的Kotlin协程三部曲(上)——概念启蒙篇
  18. java进程、线程知识扩充
  19. linux下更新Cmake,包括cmake下载缓慢解决方案
  20. 华为做raid5步骤_华为2288hV3服务器创建RAID步骤.docx

热门文章

  1. 2022湖南最新消防设施操作员模拟试题题库及答案
  2. 你知道乌克兰的科技公司吗?他们现在的处境如何呢?
  3. [电路]12-回路电流法
  4. java API文档中文版 网盘下载
  5. Win10彻底删除OneDrive的方法
  6. 123网盘无法下载问题解决
  7. 统计学基础——负二项分布的数字特征
  8. 整数规划学习笔记(一)
  9. 【转】EBS财务系统总账模块(GL)会计期间状态总结
  10. VS打开后界面找不到win32或者x64的选项怎么办?