手写SpringMVC思路

1.web.xml加载

 为了读取web.xml中的配置,我们用到ServletConfig这个类,它代表当前Servlet在web.xml中的配置信息。通过web.xml中加载我们自己写的MyDispatcherServlet和读取配置文件。

2、初始化阶段

  在前面我们提到DispatcherServlet的initStrategies方法会初始化9大组件,但是这里将实现一些SpringMVC的最基本的组件而不是全部,按顺序包括:

  • 加载配置文件
  • 扫描用户配置包下面所有的类
  • 拿到扫描到的类,通过反射机制,实例化。并且放到ioc容器中(Map的键值对 beanName-bean) beanName默认是首字母小写
  • 初始化HandlerMapping,这里其实就是把url和method对应起来放在一个k-v的Map中,在运行阶段取出

3、运行阶段

  每一次请求将会调用doGet或doPost方法,所以统一运行阶段都放在doDispatch方法里处理,它会根据url请求去HandlerMapping中匹配到对应的Method,然后利用反射机制调用Controller中的url对应的方法,并得到结果返回。按顺序包括以下功能:

  • 异常的拦截
  • 获取请求传入的参数并处理参数
  • 通过初始化好的handlerMapping中拿出url对应的方法名,反射调用

手写SpringMVC基本实现

/**
* 手写SpringMVC框架 作者:每特教育-余胜军<br>
*
* @QQ644064779 1.自定义DispatcherServlet<br>
* 2.servlet init()方法初始化###只会执行一次<br>
* ######2.1获取当前包下所有的类<br>
* ######2.2初始化当前包下所有的类,使用Java反射机制初始化对象存放在SpringMVC容器中key(beanId)-
* value( 当前实例对象) <br>
* ######2.3初始化HandlerMapping方法,将url和方法对应上 <br>
* ########2.3.1使用Java反射技术读取类的信息,存放在map集合中key为url请求地址,value为对应方法
* <br>
* ########2.3.2使用Java反射技术读取类的信息,存放在map集合中key为url请求地址,value为对应实例对象
* <br>
* 3.servlet get或者post请求<br>
* ######## 3.1.1获取请求地址,使用Java反射技术找到对应的方法和实例对象进行执行 <br>
*/
public class ExtDispatcherServlet extends HttpServlet {
// mvc bean key=beanid ,value=对象
private ConcurrentHashMap<String, Object> mvcBeans = new ConcurrentHashMap<String, Object>();
// mvc 请求方法 key=requestUrl,value=对象
private ConcurrentHashMap<String, Object> mvcBeanUrl = new ConcurrentHashMap<String, Object>();
// mvc 请求方法 key=requestUrl,value=方法
private ConcurrentHashMap<String, String> mvcMethodUrl = new ConcurrentHashMap<String, String>(); /**
* 初始化自定义SpringMVC容器
*/
public void init() throws ServletException {
try {
// 1.获取当前包下所有的类
List<Class<?>> classes = ClassUtil.getClasses("com.itmayiedu.ext.controller");
// 2.初始化当前包下所有的类,使用Java反射机制初始化对象存放在SpringMVC容器中key(beanId)-value(
// 当前实例对象)
findClassMVCBeans(classes);
// 3.初始化HandlerMapping方法,将url和方法对应上
handlerMapping(mvcBeans); } catch (Exception e) { }
} // 2.初始化当前包下所有的类,使用Java反射机制初始化对象存放在SpringMVC容器中key(beanId)-value(
// 当前实例对象)
public void findClassMVCBeans(List<Class<?>> classes)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
mvcBeans = new ConcurrentHashMap<String, Object>();
for (Class<?> classInfo : classes) {
ExtController extController = classInfo.getDeclaredAnnotation(ExtController.class);
if (extController != null) {
// 默认类名小写 作为bean的名称
String beanId = ClassUtil.toLowerCaseFirstOne(classInfo.getSimpleName());
mvcBeans.put(beanId, ClassUtil.newInstance(classInfo));
}
} } // 3.初始化HandlerMapping方法,将url和方法对应上
public void handlerMapping(ConcurrentHashMap<String, Object> mvcBeans) {
// 遍历mvc bean对象
for (Map.Entry<String, Object> entry : mvcBeans.entrySet()) {
// springmvc 注入object对象
Object mvcObject = entry.getValue();
// 判断类上是否有@ExtRequestMapping注解
Class<? extends Object> classInfo = mvcObject.getClass();
String requestBaseUrl = null;
ExtRequestMapping classExtRequestMapping = classInfo.getAnnotation(ExtRequestMapping.class);
if (classExtRequestMapping != null) {
requestBaseUrl = classExtRequestMapping.value();
}
// 遍历当前类的所有方法,判断方法上是否有注解
Method[] declaredMethods = classInfo.getDeclaredMethods();
for (Method method : declaredMethods) {
ExtRequestMapping methodExtRequestMapping = method.getDeclaredAnnotation(ExtRequestMapping.class);
if (methodExtRequestMapping != null) {
String httpRequestUrl = methodExtRequestMapping.value();
mvcBeanUrl.put(requestBaseUrl + httpRequestUrl, mvcObject);
mvcMethodUrl.put(requestBaseUrl + httpRequestUrl, method.getName());
}
}
}
} @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
doDispatch(req, resp);
} catch (Exception e) {
// TODO: handle exception
}
} public void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
// 1.获取请求url地址
String requestUrl = req.getRequestURI();
// 2.使用请求url查找对应mvc 控制器bean
Object object = mvcBeanUrl.get(requestUrl);
if (object == null) {
resp.getWriter().println("http ext not found controller 404");
return;
}
// 3.获取对应的请求方法
String methodName = mvcMethodUrl.get(requestUrl);
if (StringUtils.isEmpty(methodName)) {
resp.getWriter().println("http ext not found Method 404");
return;
}
// 4.使用java反射技术执行方法
Class<? extends Object> classInfo = object.getClass();
String resultPage = (String) methodInvoke(classInfo, object, methodName);
// 5.视图展示
viewdisplay(resultPage, req, resp);
} // 执行方法
public Object methodInvoke(Class<? extends Object> classInfo, Object object, String methodName) {
try {
Method method = classInfo.getMethod(methodName);
Object result = method.invoke(object);
return result;
} catch (Exception e) {
e.printStackTrace();
return null;
}
} // 视图展示
public void viewdisplay(String pageName, HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// 获取后缀信息
String suffix = ".jsp";
// 页面目录地址
String prefix = "/";
req.getRequestDispatcher(prefix + pageName + suffix).forward(req, res);
} }

《四 spring源码》手写springmvc的更多相关文章

  1. spring源码学习之springMVC(一)

    个人感觉<Spring技术内幕:深入解析Spring架构与设计原理(第2版)>这本书对spring的解读要优于<Spring源码深度解析(第2版)>这本书的,后者感觉就是再陈述 ...

  2. 《四 spring源码》手写springioc框架

    手写SpringIOCXML版本 /** * 手写Spring专题 XML方式注入bean * * * */ public class ClassPathXmlApplicationContext { ...

  3. 《四 spring源码》利用TransactionManager手写spring的aop

    事务控制分类 编程式事务控制          自己手动控制事务,就叫做编程式事务控制. Jdbc代码: Conn.setAutoCommite(false);  // 设置手动控制事务 Hibern ...

  4. 史上最完整promise源码手写实现

    史上最完整的promise源码实现,哈哈,之所以用这个标题,是因为开始用的标题<手写promise源码>不被收录 promise自我介绍 promise : "君子一诺千金,承诺 ...

  5. 【spring源码学习】springMVC之映射,拦截器解析,请求数据注入解析,DispatcherServlet执行过程

    [一]springMVC之url和bean映射原理和源码解析 映射基本过程 (1)springMVC配置映射,需要在xml配置文件中配置<mvc:annotation-driven >  ...

  6. 《四 spring源码》spring的事务注解@Transactional 原理分析

    先了解什么是注解 注解 Jdk1.5新增新技术,注解.很多框架为了简化代码,都会提供有些注解.可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件. 注解不会也不能影 ...

  7. spring源码学习之springMVC(二)

    接着上一篇.继续来看springMVC中最和我们开发中接近的一部分内容: DispatcherServlet的逻辑处理 作者写到在DispatcherServlet类中存在doGet.doPost之类 ...

  8. Spring源码追踪4——SpringMVC View解析

    这次的议题是返回json和返回普通view经过的路线差异. ---------------------------------------------------------------------- ...

  9. Ubuntu搭建Spring源码环境常见问题

    在一心想要学习Spring框架源码时,我们会遇到很多麻烦的问题.开始本文前,你只需要拥有一个装好IDEA的Ubuntu系统就可以愉快启程了.如果还没有IDEA,可以参考在Ubuntu上安装Intell ...

随机推荐

  1. python raw string

    path = r'C:\a\b\c.txt' r'字符串' 是raw 字符串的意思, 其中的字符串不会转义,即不解释 \ . 作用之一:可以用来保存Windows的路径,直接从资源管理器复制来粘贴,不 ...

  2. docker基础用法

    docker 架构: docker 安装前期准备: 安装centos7 ,不要在centos6  [root@node01 yum.repos.d]# uname -a Linux node01 -. ...

  3. UOJ_21_【UR #1】缩进优化_数学

    UOJ_21_[UR #1]缩进优化_数学 题面:http://uoj.ac/problem/21 最小化$\sum\limits{i=1}^{n}a[i]/x+a[i]\;mod\;x$ =$\su ...

  4. MongoDB中的一些坑(最好不要用)

    MongoDB 是目前炙手可热的 NoSQL 文档型数据库,它提供的一些特性很棒:如自动 failover 机制,自动 sharding,无模式 schemaless,大部分情况下性能也很棒.但是薄荷 ...

  5. HDU1540(线段树统计连续长度)

    ---恢复内容开始--- Tunnel Warfare Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d &am ...

  6. POJ2253(djkstra求最长最短边)

    Frogger Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 32257   Accepted: 10396 Descrip ...

  7. ReSIProcate环境搭建

    1首先下载resiprocate-1.6 2取消resiprocate-1.6目录的只读属性 3然后使用Visual Studio 2008打开resiprocate-1.6下的reSIProcate ...

  8. Jasper-Api:接口测试

    ylbtech-Jasper-Api:接口测试 1. EditTerminal返回顶部 1. /// <remarks/> [System.Web.Services.Protocols.S ...

  9. UI 界面:技术决定一切

    转自:http://www.cnblogs.com/NEOCSL/archive/2012/12/10/2811153.html 在我看来,肖恩帕克不仅仅是一位技术天才和远见卓识的移动互联网领域先锋. ...

  10. node.js setup wizard ended prematurely Win7安装nodejs失败解决方法

    笔记本win7在nodejs官方网站下载.msi文件安装,安装到一半的时候,进度条提示:roll back,because of a error.node.JS setup wizard ended ...