自己动手写一个spring之MVC_2

发布时间:2026/7/17 21:51:22

自己动手写一个spring之MVC_2
写在前面源码 。在前面的文章中controller层的bean我们并没有使用IOC容器管理起来并且DispatcherServlet的职责过去繁重了完全不符合单一职责的原则所以本文也会对DispatcherServlet进行拆解。1增加controller的IOC容器老规矩如下类publicclassXmlWebApplicationContextextendsClassPathXmlApplicationContextimplementsWebApplicationContext{privateServletContextservletContext;// ...}为了能够方便从contextloadlistenr创建的容器中获取bean信息我们可以引入父子容器的概念listener初始化的作为父容器controller的容器作为子容器这样如果controller中要获取service bean或其他的bean的时候就可以从父容器中获取了因此如下修改dispacherservletpackagecom.hc.minispring.web.v4_split_dispatcher;publicclassDispatcherServletextendsHttpServlet{// ...privateWebApplicationContextwebApplicationContext;privateWebApplicationContextparentApplicationContext;// ...publicDispatcherServlet(){super();}Overridepublicvoidinit(ServletConfigconfig)throwsServletException{super.init(config);// 获取在contextloadlistener中初始化的父容器this.parentApplicationContext(WebApplicationContext)this.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);// ...// 创建controller的子容器this.webApplicationContextnewAnnotationConfigWebApplicationContext(sContextConfigLocation,this.parentApplicationContext);// ...}}既然引入了父子容器那么我们最重要的容器类DefaultListableBeanFactory也要支持了增加方法设置父容器// com.hc.minispring.ioc.four_beanfactory_and_event.beans.factory.support.DefaultListableBeanFactorypublicclassDefaultListableBeanFactoryextendsAbstractAutowireCapableBeanFactoryimplementsConfigurableListableBeanFactory{OverridepublicvoidsetParent(ConfigurableListableBeanFactorybeanFactory){this.parentbeanFactory;}}获取bean也要尝试从父容器中获取了// com.hc.minispring.ioc.four_beanfactory_and_event.beans.factory.support.DefaultListableBeanFactoryOverridepublicObjectgetBean(StringbeanName)throwsBeansException{Objectresultsuper.getBean(beanName);// 如果当前ioc容器没有则尝试从父容器中查找if(resultnull){// result this.parentBeanFctory.getBean(beanName);resultthis.parent.getBean(beanName);}returnresult;}2拆解dispatcher servlet2.1处理请求当前dispatcher servlet处理请求的代码如下protectedvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{StringsPathrequest.getServletPath();// ...try{Methodmethodthis.mappingMethods.get(sPath);objthis.mappingObjs.get(sPath);objResultmethod.invoke(obj);}catch(SecurityExceptione){// ...}response.getWriter().append(objResult.toString());}可以看到获取处理请求的方法以及处理方法的执行在这里都一股脑全做了这完全不符合单一职责的原则并且扩展性也很弱比如增加一种获取处理请求方法的方式。所以需要对这一块进行一番改造。对于根据请求获取具体请求方法的职责我们定义如下接口// 职责根据请求信息获取处理请求的方法方法对象controller中的某个方法publicinterfaceHandlerMapping{HandlerMethodgetHandler(HttpServletRequestrequest)throwsException;}对于处理请求方法执行的职责定义如下接口/** * 职责负责执行具体controller的方法 */publicinterfaceHandlerAdapter{voidhandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException;}对应的针对当前使用RequestMapping映射请求的场景分别定义具体实现类RequestMappingXxx:packagecom.hc.minispring.web.v4_split_dispatcher;// .../** * 基于RequestMapping注解的url映射类 */publicclassRequestMappingHandlerMappingimplementsHandlerMapping{WebApplicationContextwac;privatefinalMappingRegistrymappingRegistrynewMappingRegistry();// ...}packagecom.hc.minispring.web.v4_split_dispatcher;importjava.io.IOException;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importcom.hc.minispring.web.v3_ioc.WebApplicationContext;/** * 基于RequestMapping注解的具具体执行方法实现类 */publicclassRequestMappingHandlerAdapterimplementsHandlerAdapter{WebApplicationContextwac;// ...}另外对于映射信息的维护职责定义类/** * 职责维护request到处理请求方法 */publicclassMappingRegistry{privateListStringurlMappingNamesnewArrayList();privateMapString,ObjectmappingObjsnewHashMap();privateMapString,MethodmappingMethodsnewHashMap();// ...}另外修改请求入口方法doGet为service这样可以处理各种类型的请求对应的修改Dispatcherservletpackagecom.hc.minispring.web.v4_split_dispatcher;// .../** * Servlet implementation class DispatcherServlet */publicclassDispatcherServletextendsHttpServlet{// ...// 修改点使用新组件处理请求privateHandlerMappinghandlerMapping;privateHandlerAdapterhandlerAdapter;Overridepublicvoidinit(ServletConfigconfig)throwsServletException{// ...}protectedvoidRefresh(){initController();// 修改点初始化handlermapping和handleradapterinitHandlerMappings(this.webApplicationContext);initHandlerAdapters(this.webApplicationContext);// ...}// 修改点service作为servlet入口这样可以处理各种类型的请求Overrideprotectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse){request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.webApplicationContext);try{doDispatch(request,response);}catch(Exceptione){e.printStackTrace();}finally{}}protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{HttpServletRequestprocessedRequestrequest;HandlerMethodhandlerMethodnull;// 修改点使用新组件获取处理请求的方法handlerMethodthis.handlerMapping.getHandler(processedRequest);if(handlerMethodnull){return;}// 修改点使用新组件处理请求即调用目标方法HandlerAdapterhathis.handlerAdapter;ha.handle(processedRequest,response,handlerMethod);}}3测试web.xml:?xml version1.0 encodingUTF-8?web-appxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:webhttp://xmlns.jcp.org/xml/ns/javaeexsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsdidWebApp_IDcontext-paramparam-namecontextConfigLocation/param-name!-- param-valueapplicationContext.xml/param-value--param-valuemvc_split_dispatcher/applicationContext.xml/param-value/context-paramlistenerlistener-classcom.hc.minispring.web.v3_ioc.ContextLoaderListener/listener-class/listenerservletservlet-nameminisMVC/servlet-nameservlet-classcom.hc.minispring.web.v4_split_dispatcher.DispatcherServlet/servlet-classinit-paramparam-namecontextConfigLocation/param-nameparam-value/WEB-INF/minisMVC-servlet.xml/param-value/init-paramload-on-startup1/load-on-startup/servletservlet-mappingservlet-nameminisMVC/servlet-nameurl-pattern//url-pattern/servlet-mapping/web-appioc配置文件applicationContext.xml:?xml version1.0 encodingUTF-8?beansbeanidaserviceclasscom.hc.minispring.web.v4_split_dispatcher.test.AServiceImpl//beansservelt配置文件minisMVC-servlet.xml?xml version1.0 encodingUTF-8 ?components!-- component-scan base-packagecom.hc.minispring.web.v2.test /--component-scanbase-packagecom.hc.minispring.web.v4_split_dispatcher.controller//componentscontrollerpublicclassHelloController{AutowiredprivateAServiceaservice;RequestMapping(/hello1527)publicStringdoTest(){returnaservice.sayHello();}}启动测试写在后面参考文章列表手把手带你写一个 MiniSpring 。

相关新闻

XXE漏洞实战:3种主流编程语言(PHP/Java/Python)防御代码对比与绕过

XXE漏洞实战:3种主流编程语言(PHP/Java/Python)防御代码对比与绕过

2026/7/8 9:26:33

XXE漏洞防御实战:PHP/Java/Python安全编码对比与深度防护策略1. 漏洞原理与危害全景分析XXE(XML External Entity Injection)漏洞的本质是XML解析器对外部实体的不当处理。当应用程序解析用户可控的XML输入时,若未正确配置安全参数…

Harness Engineering与Hermes Agent企业级AI编程实战指南

Harness Engineering与Hermes Agent企业级AI编程实战指南

2026/7/7 3:16:07

🚀 30款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度 这次我们来看一个关于 Harness Engineering 和 Hermes Agent 的实战教程项目。这个项目重点不是讲概念有多复杂,而是能不能…

Python 加密与解密实战 18 招(四):文件加密·扩展算法·安全随机数

Python 加密与解密实战 18 招(四):文件加密·扩展算法·安全随机数

2026/7/7 3:05:56

Python 加密与解密实战 18 招(四):文件加密扩展算法安全随机数 系列文章导航 第一篇:散列哈希加密(招式1-4) 第二篇:对称加密(招式5-9) 第三篇:非对称加密数字签名密钥交换(招式10-13) 第四篇:文件加密扩展算法安全随机数(招式14-18) ← 当前 前言 本篇是系列的…

云智能制造一体化平台【程序源代码】

云智能制造一体化平台【程序源代码】

2026/7/17 21:41:53

关键字:智能制造,零代码,SaaS,Spring Cloud Alibaba,Vue3,uni-app,MySQL,Mybatis-Plus, 工作流,ERP,MES,CRM,OA, 多租户项目介绍: 云智能制造一体化平台(含源码)开源组织推出的一站式 SaaS 智能制造管理平台…

光伏热斑检测数据集 | 2700张YOLO光伏缺陷检测数据集

光伏热斑检测数据集 | 2700张YOLO光伏缺陷检测数据集

2026/7/17 21:41:53

光伏热斑检测数据集 | 2700张YOLO光伏缺陷检测数据集 一、数据集概述 本数据集面向光伏发电运维场景,用于光伏组件热斑缺陷的检测,共包含约2700张高质量标注图像。热斑效应是光伏组件因局部遮挡、隐裂或老化等原因导致的局部异常发热现象,是…

记忆翻牌小游戏微信小程序【程序源代码】

记忆翻牌小游戏微信小程序【程序源代码】

2026/7/17 21:41:53

关键字:uni-app, 记忆翻牌,小游戏,微信小程序,H5, 多端,休闲游戏,卡牌配对,关卡,音效项目名称:记忆翻牌小游戏微信小程序项目介绍本记忆翻牌小游戏基于 uni-app 跨端框架…

高仿蜜雪冰城小程序【程序源代码】

高仿蜜雪冰城小程序【程序源代码】

2026/7/17 21:41:53

(一)系统介绍1.1 系统介绍高仿蜜雪冰城小程序(含源码)本系统选择微信小程序原生开发 云CMS技术,运用了微信云集合数据库为后台数据库,将用户分为管理员、用户两大类,系统实现了首页、该系统采用…

Div.2 CF 1105A题(位运算,贪心)

Div.2 CF 1105A题(位运算,贪心)

2026/7/17 21:41:53

题目链接:https://codeforces.com/contest/2240/problem/A 题目大意: 给你两个数 n 和 k。 你要构造 k 个非负整数(也就是 a₁, a₂, …, aₖ),要求: 这 k 个数的总和 不超过 n; 所有数的二进…

Blender阵列修改器驱动Seedance 2.0动态字阵生成

Blender阵列修改器驱动Seedance 2.0动态字阵生成

2026/7/17 21:31:53

1. 项目概述:当AI字形生成遇上Blender工业级阵列排布Seedance 2.0 这个名字最近在设计圈和AIGC社区里出现频率很高,它不是传统意义上的建模软件,而是一个专注「动态字形生成」的AI工具——尤其擅长把单个文字或短语,自动转化为具有…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/17 10:50:47

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/17 17:34:09

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/16 14:18:17

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

Cursor终端插件生态避坑指南:23个实测低效插件黑名单,附3个自研轻量替代方案

Cursor终端插件生态避坑指南:23个实测低效插件黑名单,附3个自研轻量替代方案

2026/7/17 0:00:57

更多请点击: https://intelliparadigm.com 第一章:Cursor终端插件生态避坑指南概览 Cursor 作为基于 VS Code 内核构建的 AI 原生编辑器,其终端插件生态虽活跃,但存在兼容性断层、权限策略突变与调试链路断裂等典型风险。开发者常…

ChatGPT写作提示词效率革命:单条提示词响应质量提升3.8倍的关键变量(附可复用提示词矩阵表)

ChatGPT写作提示词效率革命:单条提示词响应质量提升3.8倍的关键变量(附可复用提示词矩阵表)

2026/7/17 0:00:57

更多请点击: https://codechina.net 第一章:ChatGPT写作提示词效率革命:单条提示词响应质量提升3.8倍的关键变量(附可复用提示词矩阵表) 提示词工程已从经验试错迈入变量驱动的科学阶段。实证研究表明,影响…

DeepSeek V4替换Codex底座模型的实践与优化

DeepSeek V4替换Codex底座模型的实践与优化

2026/7/17 0:00:57

1. 为什么选择用DeepSeek V4替换Codex的底座模型去年我在开发一个智能代码补全工具时,发现Codex的默认底座模型在复杂业务逻辑场景下表现不尽如人意。经过多次测试对比,DeepSeek V4在以下几个关键指标上展现出明显优势:代码补全准确率&#x…