手写模拟SpringMvc源码
Posted 我要学习java和python
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写模拟SpringMvc源码相关的知识,希望对你有一定的参考价值。
MVC框架
MVC是一种设计模式(设计模式就是日常开发中编写代码的一种好的方法和经验的总结)。模型(model)-视图(view)-控制器(controller),三层架构的设计模式。用于实现前端页面的展现与后端业务数据处理的分离。
Spring MVC的主要组件
前端控制器 DispatcherServlet
Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应。此模块不需要程序员开发。
作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
处理器映射器HandlerMapping
此功能不需要程序员开发。
作用:根据请求的URL来查找Handler
处理器适配器HandlerAdapter
作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)
视图View
需要程序员开发jsp。View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)
用户发送请求至前端控制器DispatcherServlet;
DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
DispatcherServlet 调用 HandlerAdapter处理器适配器;
HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
Handler执行完成返回ModelAndView;
HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
ViewResolver解析后返回具体View;
DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
DispatcherServlet响应用户。
手写模拟SpringMvc源码
spring mvc调用到Controller执行的原理
通过加载配置文件web.xml进而加载spring-mvc.xml。
根据配置文件给定的目录来扫描整个项目。
扫描所有加了@Controller注解的类。
当扫描到加了@Controller注解的类之后遍历里面所有的方法。
拿到方法对象之后 解析方法上面是否加了@RequestMapping注解。
定义一个Map集合把@RequstMapping的value 与方法对象绑定起来,即Map<String,Method>。
定义一个Map把声名该方法的类的对象绑定起来,即Map<String,Object>。
拦截到请求之后拿到请求的URI。
处理请求,例如执行指定方法,返回字符串或跳转到相应视图。
目录
导入依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 解析xml文件-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
代码
DispatcherServlet类
public class DispatcherServlet extends HttpServlet
private ApplicationContext applicationContext;
private List<MyHandle> myHandleList=new ArrayList<>();
@Override
public void init() throws ServletException
String contextConfigLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
System.out.println(contextConfigLocation);
applicationContext = new ApplicationContext(contextConfigLocation);
applicationContext.refresh();
initHandleMappinng(applicationContext);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
excuteDispatch(req,resp);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
public void initHandleMappinng(ApplicationContext applicationContext)
if(applicationContext.beanDefinitionConcurrentHashMap.size()==0)
throw new RuntimeException("Spring容器为空");
for (Map.Entry<String, BeanDefinition> stringBeanDefinitionEntry : applicationContext.beanDefinitionConcurrentHashMap.entrySet())
Class clazz = stringBeanDefinitionEntry.getValue().getClazz();
for (Method declaredMethod : clazz.getDeclaredMethods())
boolean annotationPresent = declaredMethod.isAnnotationPresent(RequestMapping.class);
if(annotationPresent==true)
String value = declaredMethod.getAnnotation(RequestMapping.class).value();
MyHandle myHandle=new MyHandle(value,declaredMethod,clazz);
myHandleList.add(myHandle);
public void excuteDispatch(HttpServletRequest request,HttpServletResponse response)
MyHandle handle = getHandle(request);
if(handle==null)
try
response.getWriter().print("404");
catch (IOException e)
e.printStackTrace();
else
Method method = handle.getMethod();
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] params=new Object[parameterTypes.length];
Map<String, String[]> parameterMap = request.getParameterMap();
for (Map.Entry<String, String[]> stringEntry : parameterMap.entrySet())
String key = stringEntry.getKey();
String value = stringEntry.getValue()[0];
int i = GetRequestParams(method, key);
if(i>=0)
params[i]=value;
else
//反射获取的是arg0,官方这里用的不是反射机制
try
Object invoke = method.invoke(handle.getClazz().newInstance(), params);
PrintWriter writer = response.getWriter();
writer.print(invoke);
catch (IllegalAccessException e)
e.printStackTrace();
catch (InvocationTargetException e)
e.printStackTrace();
catch (InstantiationException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
public MyHandle getHandle(HttpServletRequest request)
String requestURI = request.getRequestURI();
for (MyHandle myHandle : myHandleList)
if(myHandle.getUrl().equals(requestURI))
return myHandle;
return null;
public int GetRequestParams(Method method,String name)
Parameter[] parameters = method.getParameters();
for (int i=0;i<parameters.length;i++)
boolean annotationPresent = parameters[i].isAnnotationPresent(RequestParam.class);
if(annotationPresent)
String value = parameters[i].getAnnotation(RequestParam.class).value();
if(value.equals(name))
return i;
return -1;
XmlPaser类
public class XmlPaser
public static String getbasePackage(String xml)
SAXReader saxReader=new SAXReader();
InputStream inputStream = XmlPaser.class.getClassLoader().getResourceAsStream(xml);
try
Document document = saxReader.read(inputStream);
Element rootElement = document.getRootElement();
Element componentScan = rootElement.element("component-scan");
Attribute attribute = componentScan.attribute("base-package");
String text = attribute.getText();
return text;
catch (DocumentException e)
e.printStackTrace();
return "";
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">
<display-name>Application</display-name>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.example.demo.springmvc.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
代码下载地址:https://download.csdn.net/download/qq_43649937/87558006
以上是关于手写模拟SpringMvc源码的主要内容,如果未能解决你的问题,请参考以下文章