自定义一个简化版的MVC框架
1. 项目概述
本项目是一个基于Java实现的自定义MVC框架,模仿Spring MVC的核心功能,提供了注解驱动的控制器、请求映射、依赖注入、异常处理等功能。框架设计简洁明了,代码结构清晰,适合作为学习MVC框架原理的教学案例。
1.1 功能特性
- 注解驱动的控制器和服务组件
- URL路径映射与请求处理
- 依赖注入(IoC容器)
- JSON请求体解析与响应
- 全局异常处理
- 视图解析与转发
1.2 技术栈
- Java 8+
- Servlet API
- 反射机制
- 正则表达式
- JSON解析
2. 项目结构
2.1 目录结构
my-mvc/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── com/
│ │ │ │ ├── weh/
│ │ │ │ │ ├── demo/ # 示例代码
│ │ │ │ │ │ ├── controller/
│ │ │ │ │ │ ├── handler/
│ │ │ │ │ │ ├── pojo/
│ │ │ │ │ │ └── service/
│ │ │ │ │ └── framework/ # 核心框架代码
│ │ │ │ │ ├── annotation/ # 自定义注解
│ │ │ │ │ ├── pojo/ # 数据模型
│ │ │ │ │ ├── servlet/ # 核心Servlet
│ │ │ │ │ └── util/ # 工具类
│ │ ├── resources/
│ │ │ └── springmvc.properties # 框架配置文件
│ │ └── webapp/
│ │ ├── WEB-INF/
│ │ │ └── web.xml # Web配置
│ │ └── index.jsp
│ └── test/
└── pom.xml

2.2 核心组件
| 模块 | 主要职责 | 文件位置 | 说明 |
|---|---|---|---|
| 注解模块 | 定义框架所需的各种注解 | com.weh.framework.annotation | 包括控制器、请求映射、依赖注入等注解 |
| 核心Servlet | 处理请求和响应 | com.weh.framework.servlet.MyDispatcherServlet | 框架的核心控制器,负责请求分发和处理 |
| 数据模型 | 封装处理器信息 | com.weh.framework.pojo.Handler | 存储控制器、方法和参数映射信息 |
| 工具类 | 提供JSON处理等功能 | com.weh.framework.util.JsonUtil | 处理JSON的序列化和反序列化 |
| 异常处理 | 全局异常处理机制 | com.weh.framework.annotation.MyControllerAdvice | 定义全局异常处理器 |
3. 核心功能实现
3.1 注解系统
框架定义了以下核心注解:
| 注解名称 | 作用 | 目标元素 | 说明 |
|---|---|---|---|
| @MyController | 标记控制器类 | 类 | 类似Spring的@Controller |
| @MyService | 标记服务类 | 类 | 类似Spring的@Service |
| @MyAutowired | 依赖注入 | 字段 | 类似Spring的@Autowired |
| @MyRequestMapping | 请求路径映射 | 类/方法 | 类似Spring的@RequestMapping |
| @MyRequestBody | 请求体解析 | 参数 | 类似Spring的@RequestBody |
| @MyResponseBody | 响应体处理 | 方法 | 类似Spring的@ResponseBody |
| @MyControllerAdvice | 全局异常处理类 | 类 | 类似Spring的@ControllerAdvice |
| @MyExceptionHandler | 异常处理方法 | 方法 | 类似Spring的@ExceptionHandler |
3.2 核心Servlet实现
MyDispatcherServlet是框架的核心组件,负责处理所有HTTP请求。其主要工作流程如下:
-
初始化阶段:
- 加载配置文件(springmvc.properties)
- 扫描指定包路径下的类
- 初始化IoC容器,实例化标记了@MyController和@MyService的类
- 实现依赖注入,处理@MyAutowired注解
- 构建处理器映射,将URL与方法关联
- 初始化异常处理器映射
-
请求处理阶段:
- 根据请求URL查找对应的处理器
- 解析请求参数,包括URL参数和JSON请求体
- 执行处理器方法
- 处理返回结果,支持JSON响应和视图转发
- 捕获并处理异常
3.3 IoC容器实现
框架使用简单的Map实现IoC容器,存储所有被注解标记的Bean:
- 对于@MyController标记的类,使用类名首字母小写作为Bean名称
- 对于@MyService标记的类,使用注解值或类名首字母小写作为Bean名称
- 同时将实现的接口也作为Bean名称的一部分,便于按接口类型注入
3.4 依赖注入实现
依赖注入通过反射实现,处理@MyAutowired注解:
- 遍历容器中所有Bean的字段
- 查找标记了@MyAutowired注解的字段
- 根据注解值或字段类型从IoC容器中获取对应的Bean
- 通过反射设置字段值
3.5 请求处理流程
- 请求映射:使用正则表达式匹配请求URL与处理器
- 参数绑定:
- 解析URL参数
- 处理HttpServletRequest和HttpServletResponse参数
- 解析JSON请求体(@MyRequestBody)
- 方法调用:通过反射调用处理器方法
- 响应处理:
- 对于@MyResponseBody注解的方法,返回JSON
- 对于返回字符串的方法,转发到对应的JSP视图
3.6 异常处理机制
框架实现了全局异常处理机制:
- 通过@MyControllerAdvice标记异常处理类
- 通过@MyExceptionHandler标记异常处理方法
- 捕获请求处理过程中的异常,调用对应的异常处理方法
- 支持返回JSON或视图作为异常响应
4. 核心代码详解
4.1 MyDispatcherServlet核心方法
4.1.1 初始化方法
@Override
public void init(ServletConfig config) throws ServletException {
//1.加载配置文件(springmvc.properties),读取扫描包路径等配置信息
String contextConfigLocation = config.getInitParameter("contextConfigLocation");
doLoadConfig(contextConfigLocation);
// 2 扫描指定包及其子包下的所有类文件,缓存带有注解的类的全限定类名
doScan(properties.getProperty("scanPackage"));
// 3 初始化IOC容器,创建带有@MyController、@MyService、@MyControllerAdvice注解的bean实例
doInstance();
// 4 实现依赖注入,处理@MyAutowired注解,将IOC容器中的bean注入到对应字段
doAutoWired();
// 5 构建HandlerMapping处理器映射器,建立URL路径与Controller方法的映射关系
initHandlerMapping();
// 6 初始化全局异常处理器映射,注册@MyExceptionHandler标注的异常处理方法
initExceptionHandlerMapping();
System.out.println("My mvc 初始化完成....");
}
4.1.2 请求处理方法
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
Handler handler = getHandler(req);
if(handler == null) {
resp.getWriter().write("404 not found");
return;
}
// 解析参数
Class<?>[] parameterTypes = handler.getMethod().getParameterTypes();
Object[] paraValues = new Object[parameterTypes.length];
// 处理请求参数
Map<String, String[]> parameterMap = req.getParameterMap();
for(Map.Entry<String,String[]> param: parameterMap.entrySet()) {
// 处理参数...
}
// 处理HttpServletRequest和HttpServletResponse参数
if(handler.getParamIndexMapping().containsKey(HttpServletRequest.class.getSimpleName())) {
// 处理请求对象...
}
// 处理JSON请求体
if(handler.getParamIndexMapping().containsKey("@MyRequestBody")) {
// 处理JSON请求体...
}
// 调用处理器方法
Object result = handler.getMethod().invoke(handler.getController(), paraValues);
// 处理返回结果
if (result != null) {
boolean isResponseBody = handler.getMethod().isAnnotationPresent(MyResponseBody.class);
if (isResponseBody) {
// 返回JSON响应...
} else if (result instanceof String) {
// 转发到视图...
}
}
} catch (InvocationTargetException e) {
// 处理异常...
} catch (Exception e) {
// 处理异常...
}
}
4.2 注解定义
4.2.1 @MyController
@Documented // 文档注解
@Target(ElementType.TYPE) // 类注解
@Retention(RetentionPolicy.RUNTIME) // 运行时注解
public @interface MyController {
String value() default ""; // 默认值
}
4.2.2 @MyRequestMapping
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRequestMapping {
String value() default "";
}
4.3 Handler类
public class Handler {
private Object controller; // 控制器实例
private Method method; // 处理方法
private Pattern pattern; // URL匹配模式
private Map<String,Integer> paramIndexMapping; // 参数索引映射
public Handler(Object controller, Method method, Pattern pattern) {
this.controller = controller;
this.method = method;
this.pattern = pattern;
this.paramIndexMapping = new HashMap<>();
}
// getter和setter方法...
}
5. 使用指南
5.1 配置文件
在resources/springmvc.properties中配置扫描包路径:
scanPackage=com.weh.demo
5.2 Web配置
在web.xml中配置核心Servlet:
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.weh.framework.servlet.MyDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>springmvc.properties</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>
5.3 控制器开发
@MyController
@MyRequestMapping("/demo")
public class DemoController {
@MyAutowired
private Userservice userService;
@MyRequestMapping("/hello")
@MyResponseBody
public String hello() {
return "Hello, My MVC!";
}
@MyRequestMapping("/user")
@MyResponseBody
public User getUser(@MyRequestBody User user) {
return userService.getUser(user.getId());
}
}
5.4 服务层开发
@MyService
public class UserServiceImpl implements Userservice {
@Override
public User getUser(int id) {
// 业务逻辑
return new User(id, "张三");
}
}
5.5 异常处理
@MyControllerAdvice
public class ControllerAdviceHandler {
@MyExceptionHandler(Exception.class)
@MyResponseBody
public String handleException(Exception e) {
return "Error: " + e.getMessage();
}
}
6. 技术亮点
- 简洁的设计:框架结构清晰,代码量适中,易于理解和学习
- 注解驱动:使用自定义注解实现类似Spring MVC的开发体验
- 反射机制:灵活运用Java反射实现IoC容器和依赖注入
- 正则表达式:使用正则表达式实现URL匹配,支持更灵活的路径映射
- 异常处理:实现了全局异常处理机制,提高系统的健壮性
- JSON支持:内置JSON解析和序列化功能,支持RESTful风格的API
7. 性能与优化
7.1 性能考虑
- 初始化优化:框架在启动时完成扫描和初始化,运行时直接使用缓存的处理器映射
- 反射缓存:通过Handler类缓存方法和参数信息,减少反射操作的开销
- 参数解析:优化参数解析逻辑,提高请求处理速度
7.2 可能的优化方向
- 缓存机制:增加方法执行结果的缓存,减少重复计算
- 线程池:使用线程池处理请求,提高并发能力
- 路径匹配:优化URL匹配算法,提高匹配速度
- 依赖注入:实现更复杂的依赖注入场景,如构造器注入
- AOP支持:添加面向切面编程支持,增强框架功能
8. 扩展与定制
8.1 扩展注解
框架支持通过添加新的注解来扩展功能,例如:
- 添加@MyRequestParam注解,支持更灵活的参数绑定
- 添加@MySessionAttributes注解,支持会话属性管理
- 添加@MyValidated注解,支持参数验证
8.2 定制视图解析器
目前框架使用简单的JSP视图解析,可以通过扩展实现更复杂的视图解析器:
- 支持Thymeleaf、Freemarker等模板引擎
- 实现多视图解析策略
8.3 增强异常处理
可以扩展异常处理机制,支持:
- 更细粒度的异常类型处理
- 异常信息的国际化
- 异常日志的统一管理
9. 测试与部署
9.1 测试方法
- 单元测试:测试框架的核心组件和功能
- 集成测试:测试完整的请求处理流程
- 性能测试:测试框架的响应速度和并发能力
9.2 部署步骤
- 编译项目:
mvn clean package - 将生成的WAR包部署到Tomcat等Web容器
- 启动Web容器,访问应用
10. 总结
本自定义MVC框架实现了Spring MVC的核心功能,包括注解驱动、依赖注入、请求处理和异常处理等。通过学习和使用这个框架,可以更深入地理解MVC模式的实现原理,以及Java反射、Servlet等技术的应用。
框架设计简洁明了,代码结构清晰,适合作为学习MVC框架原理的教学案例,也可以作为小型项目的基础框架使用。通过扩展和优化,可以进一步增强其功能和性能,使其适用于更复杂的应用场景。
11. 附录
11.1 核心类和方法
| 类/方法 | 说明 | 位置 |
|---|---|---|
| MyDispatcherServlet | 核心控制器,处理所有HTTP请求 | com.weh.framework.servlet.MyDispatcherServlet |
| init() | 初始化方法,完成配置加载、扫描、IoC初始化等 | MyDispatcherServlet.java:39-55 |
| doPost() | 处理POST请求,包括请求解析、方法调用、响应处理 | MyDispatcherServlet.java:237-330 |
| handleException() | 处理异常,调用对应的异常处理器 | MyDispatcherServlet.java:332-397 |
| Handler | 封装处理器信息,包括控制器、方法和参数映射 | com.weh.framework.pojo.Handler |
| JsonUtil | JSON工具类,处理JSON的序列化和反序列化 | com.weh.framework.util.JsonUtil |
11.2 配置项
| 配置项 | 说明 | 默认值 |
|---|---|---|
| scanPackage | 扫描包路径,框架会扫描该路径下的所有类 | 无默认值,必须配置 |
11.3 依赖项
| 依赖 | 版本 | 用途 |
|---|---|---|
| commons-lang3 | 3.12.0 | 提供字符串处理工具 |
| jackson-databind | 2.13.0 | 提供JSON解析功能 |
11.4 示例项目
框架包含一个简单的示例项目,展示了如何使用框架开发控制器、服务和异常处理器。示例代码位于com.weh.demo包下,包括:
- DemoController:展示基本的请求处理
- UserServiceImpl:展示服务层实现
- ControllerAdviceHandler:展示异常处理
- User:数据模型类
7759



被折叠的 条评论
为什么被折叠?



