课程标题《一节课纯手写springmvc框架》
课程内容:
1.springmvc底层原理实现
2.dispatcherservlet原理
3.springmvc底层工作流程
4.一节课纯手写springmvc框架
1.SpringIOC容器初始化时开始遍历所有的bean对象 判断 bean对象 类上是否有加上
@Controller注解,如果类上有加该注解的话 则该类就是为我们控制类;
2.在容器初始化时会建立所有url和controller的对应关系,利用java反射机制,查找该控制类中所有方法,判断方法上是否有加上@RequestMapping注解,如果有加上该注解的话 保存到Map
3.定义DispatcherServlet 接受客户端所有请求 从该map集合中查找到具体的控制类 方法 调用(java
反射机制。)
所有请求过来先达到我们的DispatcherServlet 分发执行具体的方法
springmvc 结合web.xml springmvc .xml
1.自定义注解(标记哪些类是为控制类、url映射方法)
思考:用户访问路径:/mayiktDemo01 如何查找到 MayiktController#mayiktDemo01();
提前通过Map集合映射关系(key=/mayiktDemo01,MayiktController#mayiktDemo01())
2.spring ioc容器加载完毕之后 开始遍历所有的bean对象 判断 bean对象 类上是否有加上
MayiktController注解,如果类上有加该注解的话 则该类就是为我们控制类;
3.利用java反射机制 查找该类中所有方法 判断方法上是否有加上@MayiktRequestMapping 如果
有加上该注解的话 则 采用map集合存放URL映射的关系。
4.定义DispatcherServlet 接受客户端所有请求 从该map集合中查找到具体的控制类 方法 调用(java
反射机制。)
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
protected void initHandlerMethods() {
//从springioc容器中查找到所有的bean的名称
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
//根据bean的名称 从ioc容器中查找到具体的bean对象
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
Class<?> beanType = null;
try {
// 从ioc容器查找到该对象
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
//判断该对象类型 是否控制类 如果是的情况下
if (beanType != null && isHandler(beanType)) {
//
detectHandlerMethods(beanName);
}
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2Nq8w2OH-1660837592257)(https://cdn.nlark.com/yuque/0/2022/png/25438525/1658843830899-d7a8d071-8025-469b-abdd-85adfabd2df8.png)]
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- 整合springmvc框架依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<!--
使用maven tomcat插件运行
-->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<port>85</port>
<path>/</path>
<ignorePackaging>true</ignorePackaging>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
控制器注解
/**
* @author songchuanfu
* @qq 1802284273
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface MayiktController {
}
URL映射注解
package com.mayikt.ext;
import org.springframework.web.bind.annotation.Mapping;
import java.lang.annotation.*;
/**
* @author songchuanfu
* @qq 1802284273
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface MayiktRequestMapping {
String value();
}
响应json数据
package com.mayikt.ext;
import java.lang.annotation.*;
/**
* @author songchuanfu
* @qq 1802284273
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MayiktResponseBody {
}
package com.mayikt.controller;
import com.mayikt.ext.MayiktRequestMapping;
import com.mayikt.ext.MayiktResponseBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author songchuanfu
* @qq 1802284273
*/
@com.mayikt.ext.MayiktController
public class MayiktController {
/**
* 1.需要将我们的控制类注入到IOC容器;
* 2.循环遍历判断每个 bean对象 是否在类上加上@Controller注解
* 3.如果有加上@Controller注解 , 则将它存入到springmvc容器中
* 4.利用java反射机制 遍历springmvc容器中 url与控制类方法 关联
*/
/**
* 访问该接口返回json数据
*
* @return
*/
@MayiktRequestMapping("/mayiktSpringMvc")
@MayiktResponseBody
public String mayiktSpringMvc() {
return "ok";
}
/**
* 访问该接口返回json数据
*
* @return
*/
@MayiktRequestMapping("/mayikt66")
@MayiktResponseBody
public String mayikt66() {
return "mayikt66";
}
}
package com.mayikt.init;
import com.mayikt.ext.MayiktController;
import com.mayikt.ext.MayiktRequestMapping;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @author songchuanfu
* @qq 1802284273
*/
@Component
public class MayiktAbstractHandlerMethodMapping implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
/**
* 初始化 url与具体控制类方法 映射
* spring控制类名称 handler
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
//1.从ioc容器获取所有bean的对象名称
String[] beanDefinitionNames = this.applicationContext.getBeanDefinitionNames();
//2.从ioc容器获取到具体bean对象
Arrays.stream(beanDefinitionNames).forEach((beanName) -> {
Object handler = this.applicationContext.getBean(beanName);
if (handler != null) {
Class<?> handlerClass = handler.getClass();
//3.判断该类上是否有加上该控制器注解
MayiktController mayiktController = handlerClass.getDeclaredAnnotation(MayiktController.class);
if (mayiktController != null)
detectHandlerMethods(handler, handlerClass);
}
});
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private void detectHandlerMethods(Object handler, Class<?> handlerClass) {
// 4.使用java反射机制获取所有的方法 判断方法上是否有加上MayiktRequestMapping
Method[] declaredMethods = handlerClass.getDeclaredMethods();
Arrays.stream(declaredMethods).forEach((method -> {
//判断方法上是否有加上MayiktRequestMapping
MayiktRequestMapping mayiktRequestMapping = method.getDeclaredAnnotation(MayiktRequestMapping.class);
if (mayiktRequestMapping != null) {
// 注册url
// map集合 key url value 控制类、方法
String reqURL = mayiktRequestMapping.value();
// 注册存放url
MayiktMappingRegistContainer.getRegistUrl().put(reqURL+".do", new MayiktMappingRegistration(handler, method, reqURL));
}
}));
}
}
package com.mayikt.init;
import java.util.HashMap;
import java.util.Map;
/**
* @author songchuanfu
* @qq 1802284273
*/
public class MayiktMappingRegistContainer {
private static Map<String, MayiktMappingRegistration> registUrl = new HashMap<>();
public static Map<String, MayiktMappingRegistration> getRegistUrl() {
return registUrl;
}
}
package com.mayikt.ext;
import com.mayikt.init.MayiktMappingRegistContainer;
import com.mayikt.init.MayiktMappingRegistration;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
/**
* @author songchuanfu
* @qq 1802284273
*/
@WebServlet("*.do")
public class MayiktDispatcherServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
PrintWriter writer = httpServletResponse.getWriter();
try {
// 1.获取客户端访问url
String requestURI = httpServletRequest.getRequestURI();
// 2.再根据该url从 映射map集合查找对应的 handler和方法
MayiktMappingRegistration mayiktMappingRegistration
= MayiktMappingRegistContainer.getRegistUrl().get(requestURI);
if (mayiktMappingRegistration == null) {
// 没有对应的 映射handler和方法
httpServletResponse.setStatus(404);
writer.print("404");
return;
}
// 3.利用反射机制调用 handler和方法
Object handler = mayiktMappingRegistration.getHandler();
Method handlerMethod = mayiktMappingRegistration.getHandlerMethod();
// 调用 映射方法
Object result = handlerMethod.invoke(handler, null);
// 4.判断方法上是否有加上MayiktResponseBody
MayiktResponseBody mayiktResponseBody = handlerMethod.getDeclaredAnnotation(MayiktResponseBody.class);
if (mayiktResponseBody != null) {
writer.print(result);// 返回json数据
} else {
// 视图页面跳转
httpServletRequest.getRequestDispatcher((String) result).forward(httpServletRequest, httpServletResponse);
}
} catch (Exception e) {
} finally {
if (writer != null) {
writer.close();
}
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
package com.mayikt.ext;
import java.util.HashMap;
import java.util.Map;
/**
* @author songchuanfu
* @qq 1802284273
*/
public class MayiktMappingRegistContainer {
private static Map<String, MayiktMappingRegistration> registry = new HashMap<>();
public static Map<String, MayiktMappingRegistration> getRegistry() {
return registry;
}
}
package com.mayikt.ext;
import java.lang.reflect.Method;
/**
* @author songchuanfu
* @qq 1802284273
*/
public class MayiktMappingRegistration {
/**
* 控制器类
*/
private Object handler;
/**
* 具体对应的方法
*/
private Method handlerMethod;
/**
* 请求url
*/
private String mappingUrl;
public MayiktMappingRegistration(Object handler, Method handlerMethod, String mappingUrl) {
this.handler = handler;
this.handlerMethod = handlerMethod;
this.mappingUrl = mappingUrl;
}
public Object getHandler() {
return handler;
}
public void setHandler(Object handler) {
this.handler = handler;
}
public Method getHandlerMethod() {
return handlerMethod;
}
public void setHandlerMethod(Method handlerMethod) {
this.handlerMethod = handlerMethod;
}
public String getMappingUrl() {
return mappingUrl;
}
public void setMappingUrl(String mappingUrl) {
this.mappingUrl = mappingUrl;
}
public MayiktMappingRegistration() {
}
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取HttpServletRequest
HttpServletRequest processedRequest = request;
//处理器执行链由处理器对象和拦截器组成
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}