springMVC搭建流程和源码解析(零配置)
官方文档:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html
以以下代码替换原生的web.xml文件配置
public class MyWebApplicationInitializer implements WebApplicationInitializer {
//tomcat启动的时候会默认调用onstart方法
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
//使用注解方式配置(零配置)
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
//类型与使用xml方式配置
//ClassPathXmlApplicationContext
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
相当于以下传统web.xml配置:
<web-app>
<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>
<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>
AppConfig.java
package com.init;
import com.config.AppConfig;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ac=new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
DispatcherServlet servlet=new DispatcherServlet(ac);
ServletRegistration.Dynamic app = servletContext.addServlet("app", servlet);
app.setLoadOnStartup(1);
app.addMapping("/app/*");
}
}
pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>spring-mvc</finalName>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
<port>8080</port>
<uriEncoding>UTF-8</uriEncoding>
</configuration>
</plugin>
</plugins>
</build>
说明:
onstart方法之所以能被tomcat启动是因为
当META-INF/services/添加的类必定是tomcat加载的类
我们再来看@HandlesTypes(WebApplicationInitializer.class)这个注解表示将WebApplicationInitializer这个类传递给这个启动类,我们接着看源码:
//Set<Class<?>> webAppInitializerClasses这个参数是为了接受上述@HandlesTypes里的所有继承WebApplicationInitializer的子类集合
//ServletContext 这个就是上下文对象 是tomcat里的
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
//这个地方就是遍历参数的集合来启动子类的onStartUp方法,所以会被tomcat启动即加载
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
springMVC是如何找到请求的controller的
1:springMVC在初始化会扫描整个项目
2:扫描到所有加了controller注解的类
3:反射拿出类里面所有方法对象然后遍历
4:判断是否有@RequestMapping("/xxx")注解
5:如果有,他会维护一个map 注解得到值作为key,方法的对象作为value
6:通过request拿到请求uri(xxx) 并去map.get出来