《四 spring源码》手写springmvc
手写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的更多相关文章
- spring源码学习之springMVC(一)
个人感觉<Spring技术内幕:深入解析Spring架构与设计原理(第2版)>这本书对spring的解读要优于<Spring源码深度解析(第2版)>这本书的,后者感觉就是再陈述 ...
- 《四 spring源码》手写springioc框架
手写SpringIOCXML版本 /** * 手写Spring专题 XML方式注入bean * * * */ public class ClassPathXmlApplicationContext { ...
- 《四 spring源码》利用TransactionManager手写spring的aop
事务控制分类 编程式事务控制 自己手动控制事务,就叫做编程式事务控制. Jdbc代码: Conn.setAutoCommite(false); // 设置手动控制事务 Hibern ...
- 史上最完整promise源码手写实现
史上最完整的promise源码实现,哈哈,之所以用这个标题,是因为开始用的标题<手写promise源码>不被收录 promise自我介绍 promise : "君子一诺千金,承诺 ...
- 【spring源码学习】springMVC之映射,拦截器解析,请求数据注入解析,DispatcherServlet执行过程
[一]springMVC之url和bean映射原理和源码解析 映射基本过程 (1)springMVC配置映射,需要在xml配置文件中配置<mvc:annotation-driven > ...
- 《四 spring源码》spring的事务注解@Transactional 原理分析
先了解什么是注解 注解 Jdk1.5新增新技术,注解.很多框架为了简化代码,都会提供有些注解.可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件. 注解不会也不能影 ...
- spring源码学习之springMVC(二)
接着上一篇.继续来看springMVC中最和我们开发中接近的一部分内容: DispatcherServlet的逻辑处理 作者写到在DispatcherServlet类中存在doGet.doPost之类 ...
- Spring源码追踪4——SpringMVC View解析
这次的议题是返回json和返回普通view经过的路线差异. ---------------------------------------------------------------------- ...
- Ubuntu搭建Spring源码环境常见问题
在一心想要学习Spring框架源码时,我们会遇到很多麻烦的问题.开始本文前,你只需要拥有一个装好IDEA的Ubuntu系统就可以愉快启程了.如果还没有IDEA,可以参考在Ubuntu上安装Intell ...
随机推荐
- Cloudera Manager 5 和 CDH5 本地(离线)安装指南
http://archive.cloudera.com/cm5/redhat/6/x86_64/cm/5.0.0/RPMS/x86_64/ http://archive-primary.clouder ...
- ASM认证与口令文件
ASM认证 ORACLE ASM 实例没有数据字典,所以连接ASM 实例只能通过如下三种系统权限来进行连接: SYSASM,SYSDBA,SYSOPER. 可以通过如下三种模式来连接ASM 实例:1. ...
- BZOJ3932:[CQOI2015]任务查询系统
浅谈主席树:https://www.cnblogs.com/AKMer/p/9956734.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem.p ...
- UltraEdit注册机原理简单说明
UltraEdit注册机原理 By:大志若愚 UltraEdit 是 Windows 下一款流行的老牌文本/HEX 编辑器(非开源).UltraEdit 正被移植到 Linux 平台.该移植名为 UE ...
- POJ3660(foyld闭包问题)
Cow Contest Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8794 Accepted: 4948 Descr ...
- Oracle字段增删改方法总结
一.修改字段的语法:alter table tablename modify (字段名 类型 [default value][null/not null],….);有一个表名为tb,字段段名为name ...
- css3 翻起页脚
html <div class="demo2"> <img src="images/1.jpg"> </div> css . ...
- JavaScript高级程序设计学习笔记第二十章--JSON
1.JSON:JavaScript Object Notation, JavaScript 对象表示法. 2.最重要的是要理解它是一种数据格式,不是一种编程语言.虽然具有相同的语法形式,但 JSON ...
- java 发邮件 代码
/** * java发送带附件的邮件 * 周枫 * 2013.8.10 */ package com.dsideal.Util; import javax.mail.*; import javax.m ...
- Java日志:集成slf4j和logback
Java日志方案有很多,包括:java.util.logging.Apache的commons-logging和log4j.slf4j以及logback. 一个大型项目会用到众多第三方jar包,这些j ...