spring mvc源码学习笔记之三
- pom.xml 内容如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qs.demo</groupId>
<artifactId>test-009</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.30.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
</dependencies>
</project>
- src/main/webapp/WEB-INF/web.xml 内容如下
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 自己指定,不用默认的 <servlet-name>-servlet.xml -->
<init-param>
<param-name>namespace</param-name>
<param-value>a</param-value>
</init-param>
<!-- 小小优化,加快首次访问速度 -->
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<!-- / 表示除了 xxx.jsp 之外的所有请求 -->
<!-- /* 表示所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- src/main/webapp/WEB-INF/templates/t01.html 内容如下
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>t01</title>
</head>
<body>
<a th:href="@{/t02}">hello</a>
</body>
</html>
- src/main/webapp/WEB-INF/templates/t02.html 内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>t01</title>
</head>
<body>
<h1>Peter</h1>
</body>
</html>
- com.qs.demo.FirstController 内容如下
package com.qs.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author qs
* @date 2024/12/20
*/
@Controller
public class FirstController {
@RequestMapping("/t01")
public String t01() {
return "t01";
}
@RequestMapping("/t02")
public String t02() {
return "t02";
}
}
以上就是全部代码
写这个例子主要是为了看名为 namespace 的 servlet init-param 。这个知识点是从 DispatcherServlet 的父类 FrameworkServlet 类中看到的。
在这个例子中,我们的 DispatcherServlet 的名字是 app,如果不指定名为 namespace 的 servlet init-param 的话,
默认情况下会去找 /WEB-INF/app-servlet.xml 来作为 DispatcherServlet 内部的 web 应用上下文的配置文件。
但是在这个例子中,我们指定了名为 namespace 的 servlet init-param,其值为 a 就意味着要找的配置文件是 a.xml。
- 额外看下 FrameworkServlet 的 javadoc
/**
* 这个 servlet 是 spring web 框架最基础的 servlet。就是它提供了 servlet 和 spring 应用上下文之间的整合。
* <p>
* Base servlet for Spring's web framework. Provides integration with
* a Spring application context, in a JavaBean-based overall solution.
* <p>
* 这个类提供了一下功能:
* 第一:为每个 servlet 管理一个web应用上下文实例。servlet 的配置是由 servlet 命名空间中的 bean 确定。
* 第二:在请求处理的时候会发布事件。不管请求是否被成功处理。
*
* <p>This class offers the following functionality:
* <ul>
* <li>Manages a {@link org.springframework.web.context.WebApplicationContext
* WebApplicationContext} instance per servlet. The servlet's configuration is determined
* by beans in the servlet's namespace.
* <li>Publishes events on request processing, whether or not a request is
* successfully handled.
* </ul>
*
* 子类可以覆盖 initFrameworkServlet 方法来对初始化过程进行自定义。
*
* <p>Subclasses must implement {@link #doService} to handle requests. Because this extends
* {@link HttpServletBean} rather than HttpServlet directly, bean properties are
* automatically mapped onto it. Subclasses can override {@link #initFrameworkServlet()}
* for custom initialization.
* <p>
* 在 servlet init-param 级别检测 contextClass 参数。没找到的话就用 XmlWebApplicationContext。
* 注意,对于默认的 FrameworkServlet ,如果要自定义应用上下文的话,自定义的应用上下文需要实现 ConfigurableWebApplicationContext。
*
* <p>Detects a "contextClass" parameter at the servlet init-param level,
* falling back to the default context class,
* {@link org.springframework.web.context.support.XmlWebApplicationContext
* XmlWebApplicationContext}, if not found. Note that, with the default
* {@code FrameworkServlet}, a custom context class needs to implement the
* {@link org.springframework.web.context.ConfigurableWebApplicationContext
* ConfigurableWebApplicationContext} SPI.
* <p>
* 接受一个可选的名为 contextInitializerClasses 的 servlet init-param。
* 这个 contextInitializerClasses 指定了一个或者多个 ApplicationContextInitializer。
* ApplicationContextInitializer 可以编程式地对 web 应用上下文进行额外配置,比如添加属性资源或者激活配置文件。
* 可以参阅 ContextLoader,这个类支持一个名为 contextInitializerClasses 的 context-param。
* 这个 context-param 对于 root web 应用上下文的作用跟这里说的名为 contextInitializerClasses 的 servlet init-param
* 对于 web 应用上下文的作用是一样的。
*
* <p>Accepts an optional "contextInitializerClasses" servlet init-param that
* specifies one or more {@link org.springframework.context.ApplicationContextInitializer
* ApplicationContextInitializer} classes. The managed web application context will be
* delegated to these initializers, allowing for additional programmatic configuration,
* e.g. adding property sources or activating profiles against the {@linkplain
* org.springframework.context.ConfigurableApplicationContext#getEnvironment() context's
* environment}. See also {@link org.springframework.web.context.ContextLoader} which
* supports a "contextInitializerClasses" context-param with identical semantics for
* the "root" web application context.
* <p>
* 这个类还会处理一个名为 contextConfigLocation 的 servlet init-param。
* 其值用逗号和空格分隔。比如 "test-servlet.xml, myServlet.xml"。
* 如果没有指定 contextConfigLocation 这个 servlet init-param 的话,则默认位置是根据 servlet 命名空间来构造的。
*
* <p>Passes a "contextConfigLocation" servlet init-param to the context instance,
* parsing it into potentially multiple file paths which can be separated by any
* number of commas and spaces, like "test-servlet.xml, myServlet.xml".
* If not explicitly specified, the context implementation is supposed to build a
* default location from the namespace of the servlet.
* <p>
* 注意:如果指定了多个配置文件,后面的 bean 定义会覆盖前面的。至少在使用 spring 默认的应用上下文的时候是这样的。
* 这样设计有个用处,就是可用于需要覆盖某些 bean 定义的场景。
*
* <p>Note: In case of multiple config locations, later bean definitions will
* override ones defined in earlier loaded files, at least when using Spring's
* default ApplicationContext implementation. This can be leveraged to
* deliberately override certain bean definitions via an extra XML file.
* <p>
* 默认的命名空间是 "'servlet-name'-servlet"。
* 比如,servlet 的名字是 test 的话,那么命名空间就是 test-servlet,对应的配置文件就是 /WEB-INF/test-servlet.xml。
* 可以用名为 namespace 的 servlet init-param 指定命名空间。
*
* <p>The default namespace is "'servlet-name'-servlet", e.g. "test-servlet" for a
* servlet-name "test" (leading to a "/WEB-INF/test-servlet.xml" default location
* with XmlWebApplicationContext). The namespace can also be set explicitly via
* the "namespace" servlet init-param.
*
* 从 spring 3.1 开始 FrameworkServlet 可以注入一个应用上下文而不是自己在内部维护。
* 这在 servlet 3.0+ 的环境中是非常有用的,servlet 3.0+ 环境支持编程式注册 servlet 实例。
* 参考 {@link #FrameworkServlet(WebApplicationContext)} 的 javadoc 。
*
* <p>As of Spring 3.1, {@code FrameworkServlet} may now be injected with a web
* application context, rather than creating its own internally. This is useful in Servlet
* 3.0+ environments, which support programmatic registration of servlet instances. See
* {@link #FrameworkServlet(WebApplicationContext)} Javadoc for details.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @author Chris Beams
* @author Rossen Stoyanchev
* @author Phillip Webb
* @see #doService
* @see #setContextClass
* @see #setContextConfigLocation
* @see #setContextInitializerClasses
* @see #setNamespace
*/