尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
前策工代——四个设计模式撑起一个政务Web框架
前、策、工、代——四个设计模式撑起一个政务Web框架文章目录前、策、工、代——四个设计模式撑起一个政务Web框架一、不是学了模式去套是写了代码回头看二、Front Controller一个Servlet接管所有请求三、StrategyTypeHandler——多态的威力四、FactoryTypeHandlerFactory ——注册表模式五、ProxyCGLIB 动态代理——IOC容器的秘密武器六、Template MethodBaseTypeHandler的模板骨架七、这四个模式不是孤立的八、结语一、不是学了模式去套是写了代码回头看这个自研框架从2008年第一行代码开始到2023年系统下线前后迭代了15年。写的时候没有刻意去用设计模式——事实上很多模式的术语是后来才知道的。但回头看框架的核心架构恰好对应了四个最经典的 GoF 模式模式框架中的位置解决了什么Front Controllerroute.java所有请求的统一入口和分发StrategyTypeHandler系列 responseFactory参数解析和响应输出的可切换策略FactoryTypeHandlerFactoryBeanFactory对象的创建、注册和依赖注入ProxyCGLIB 动态代理 proxyFilter无侵入的横切能力注入四个模式串起来就是一个完整的请求处理链路请求 → Front Controller(route) → 解析URL找到Method → Factory(BeanFactory) → 获取Controller实例 → Strategy(TypeHandler) → 解析入参类型 → 反射调用方法 → Strategy(responseFactory) → 生成响应二、Front Controller一个Servlet接管所有请求前端控制器的思想很简单不要让每个JSP/Servlet各自处理请求用一个入口统一接管。route.java继承HttpServlet配置/*拦截所有请求。核心代码在service方法里publicvoidservice(HttpServletRequestrequest,HttpServletResponseresponse){// 1. 从URL解析出方法和BeanMethodMapmothodmappraserHandler(request);// 2. 解析入参——支持 DataCenter、newDataStore、List、HashMap、基本类型paramValuespraserInParameter(request,response,mothodmap);// 3. 从BeanFactory获取Controller实例ObjecttsBeanFactory.getBean(mothodmap.getBeanid());// 4. 反射调用objmethod1.invoke(ts,paramValues);// 5. 输出响应——根据返回类型选择不同的输出策略responseFactory.getInstance().getTypeHandler(mothodmap.getReturnHandler()).parse(obj,request,response);}URL 到方法的映射是启动时建立的。BeanFactory在初始化阶段扫描所有带responseMapping注解的方法用 ASM 读取字节码拿到参数名拼成handlerMap// URL: /api/user/save → Bean: userController → Method: savehandlerMap.put(/api/user/save,methodMap);运行时praserHandler从request.getRequestURI()中提取路径直接查handlerMap。一个 HashMap 的 get 操作比任何 XML 解析、注解扫描都快。三、StrategyTypeHandler——多态的威力前端发来的参数五花八门有时候是整个 JSON 对象DataCenter有时候是数组List有时候是单个字符串int/String有时候是上传文件HashMap。如果每个 Controller 方法都自己解析参数代码重复到崩溃。TypeHandler 系列用策略模式解决了这个问题publicinterfaceTypeHandlerT{publicTparse(Objectobject)throwsTypeException;publicTparse(Objectobject,Classcls)throwsTypeException;publicTparse(Objectobject,Stringname,Classcls)throwsTypeException;}每个类型一个实现TypeHandler处理的类型怎么解析StringTypeHandlerString直接 toStringIntegerTypeHandlerint/IntegerparseInt提供默认值DateTypeHandlerDateparseDatenull时返回nullDataCenterTypeHandlerDataCenterJSON反序列化ListTypeHandlerListJSONArray → 反射实例化newDataStoreTypeHandlernewDataStoreJSON → DataStoreInputStreamTypeHandlerHashMap解析文件上传的multipart在praserInParameter里根据方法的参数类型从工厂取出对应的 TypeHandlerClassclsmothodmap.getParametertypeList().get(i);TypeHandlerhandlerTypeHandlerFactory.newInstance().getTypeHandler(cls);paramValues[i]handler.parse(rawData,mothodmap.getParameterNameList().get(i),...);业务方法不需要知道参数是怎么来的——它只需要声明(DataCenter dc, HttpServletRequest req, HttpServletResponse res)框架自动把 JSON 转成 DataCenter把 Request/Response 直接注入。同样的策略模式也用在响应输出上。responseFactory根据方法注解的responseType选择策略JSONresponse输出 JSON 字符串URLresponse跳转到 JSP 页面FileResponse输出文件下载流一个请求进来策略链从头到尾解析策略 → 业务逻辑 → 输出策略。四、FactoryTypeHandlerFactory ——注册表模式策略模式需要一个工厂来管理策略的注册和查找publicfinalclassTypeHandlerFactory{privateMapObject,TypeHandler?typeHandlerMap;privatestaticTypeHandlerFactoryfactory;privateTypeHandlerFactory(){typeHandlerMapnewHashMapObject,TypeHandler?();}publicstaticTypeHandlerFactorynewInstance(){if(factorynull){factorynewTypeHandlerFactory();factory.register(String.class,newStringTypeHandler());factory.register(int.class,newIntegerTypeHandler(0));factory.register(Integer.class,newIntegerTypeHandler(null));factory.register(Date.class,newDateTypeHandler(null));factory.register(DataCenter.class,newDataCenterTypeHandler());factory.register(List.class,newListTypeHandler());factory.register(HashMap.class,newInputStreamTypeHandler());// ... 16种类型}returnfactory;}publicTypeHandler?getTypeHandler(ClassjavaType){TypeHandlertypeHandlertypeHandlerMap.get(javaType);returntypeHandlernull?newUserObjectTypeHandler():typeHandler;}}设计要点单例全局只有一个工厂实例避免重复注册。懒加载初始化第一次调用newInstance()时注册所有 TypeHandler后续直接返回。兜底策略如果找不到精确匹配的 TypeHandler返回UserObjectTypeHandler——它用反射处理任何自定义业务对象。框架不会因为不认识的类型就崩溃。注册表可扩展如果要加一个新类型比如BigDecimal一行代码搞定factory.register(BigDecimal.class,newBigDecimalTypeHandler());五、ProxyCGLIB 动态代理——IOC容器的秘密武器BeanFactory 不仅是 Factory 模式它还是一个小型 IOC 容器。启动时扫描bean注解的类自动实例化并注入依赖publicBeanFactory(Stringurlpackage){// Step 1: 扫描包下所有类SetClass?listfindClassInPackage.getClasses(urlpackage);for(Class?cl:list){if(cl.isAnnotationPresent(bean.class)){bean d(bean)cl.getAnnotation(bean.class);if(cl.isAnnotationPresent(aoppoint.class)){// 需要AOP → 创建CGLIB代理map.put(d.id(),createproxy(cl));}else{// 不需要AOP → 直接实例化map.put(d.id(),cl.newInstance());}}}// Step 2: 注入属性property注解for(Class?cl:list){if(cl.isAnnotationPresent(bean.class)){getField(cl,map.get(...));}}}这里面代理模式起关键作用带aoppoint的类不走直接实例化而是创建 CGLIB 代理privateObjectcreateproxy(Class?cls){Callback[]callbacksnewCallback[2];callbacks[0]newdoProxy();// 走拦截链callbacks[1]newnoProxy();// 直接透传EnhancerenhancernewEnhancer();enhancer.setSuperclass(cls);enhancer.setCallbacks(callbacks);proxyFilter filternewproxyFilter();filter.setFilerList(cls.getAnnotation(aoppoint.class).filter());enhancer.setCallbackFilter(filter);// 决定哪些方法走doProxyreturnenhancer.create();}CGLIB 生成一个目标类的子类所有方法调用都先经过CallbackFilter判断在 filterList 里的方法走doProxy责任链拦截不在的走noProxy直接透传。这样业务对象的使用者完全不知道它是一个代理——它看起来就是普通的UserController但事务、日志、监控已经在代理层自动执行了。六、Template MethodBaseTypeHandler的模板骨架BaseTypeHandler用了模板方法模式。所有具体 TypeHandler 继承它只实现valueOf其他逻辑全部复用publicabstractclassBaseTypeHandlerTimplementsTypeHandlerT{// 模板方法定义骨架publicTparse(Objectobject,TdefaultValue)throwsTypeException{if(isnull(object)){// ① 空值检查returndefaultValue;}if(getType().isInstance(object)){// ② 类型匹配return(T)object;}try{returnvalueOf(object);// ③ 调用子类实现}catch(Exceptione){thrownewTypeException(...);}}// 子类只需要实现这个publicabstractTvalueOf(Objectobject)throwsTypeException;}StringTypeHandler的实现只有两行publicclassStringTypeHandlerextendsBaseTypeHandlerString{publicStringvalueOf(Objectobject){returnString.valueOf(object);}}DataCenterTypeHandler的实现也只多了 JSON 解析publicclassDataCenterTypeHandlerextendsBaseTypeHandlerDataCenter{publicDataCentervalueOf(Objectobject)throwsTypeException{DataCenterdcnewDataCenter();dc.fromJson((String)object);returndc;}}空值处理、类型比较、异常包装——这些在每个 TypeHandler 里都要做的事被BaseTypeHandler统一做了。子类只关心怎么把一个 Object 变成 T。七、这四个模式不是孤立的把它们放回一个完整的请求来看1. 浏览器发 POST /api/person/saveBody里是JSON ↓ 2. route.service() 拦截请求Front Controller ↓ 3. praserHandler() 从URL提取 /api/person/save → 查handlerMap → 拿到MethodMap ↓ 4. praserInParameter() 遍历方法的参数类型 → TypeHandlerFactory.getTypeHandler(DataCenter.class) → DataCenterTypeHandlerFactory Strategy → 解析JSON为DataCenter对象 → TypeHandlerFactory.getTypeHandler(HttpServletRequest.class) → 直接注入request ↓ 5. BeanFactory.getBean(personController) → 取实例如果是beanaoppoint返回CGLIB代理Factory Proxy ↓ 6. method.invoke(proxyInstance, params) → 实际调用走doProxy责任链 ↓ 7. 返回DataCenter → responseFactory.getTypeHandler(JSONresponse.class).parse(dc, req, res)Strategy每一步都对应一个模式每个模式都解决了一个在系统全生命周期中反复出现的需求。八、结语学设计模式的时候书上给的例子往往是鸭子、“咖啡店”、“停车场”。看完觉得懂了但真到项目里不知道怎么用。这个框架的代码是反过来的——先有业务需求怎么统一接收请求、怎么解析五花八门的参数、怎么无侵入地加事务然后自然长出了这些模式。Front Controller 不是学了才用的是所有请求都打到同一个 Servlet 上这件事做久了回头看发现它叫 Front Controller。所以学模式的真正方法不是背 GoF 20多个模式的定义是先写足够多的代码然后在自己的代码里认出那些反复出现的结构。认出来一次这个模式就再也不会忘了。
RELATED

相关推荐

CVE-2022-46169漏洞复现:Cacti监控系统命令注入原理与实战

CVE-2022-46169漏洞复现:Cacti监控系统命令注入原理与实战

1. 项目概述最近在整理内部资产的安全基线时,又看到了Cacti这个老牌监控系统的身影。作为一款基于PHP/MySQL的网络流量监测图形分析工具,它在很多企业的IT基础设施里扮演着“眼睛”的角色。然而,眼睛如果出了毛病,看到的可能就是假…

📅 2026/10/12 2:52:35
从收藏到实战:小白程序员如何以前端为基础,解锁大模型时代全栈交付能力

从收藏到实战:小白程序员如何以前端为基础,解锁大模型时代全栈交付能力

作者分享了自己从陷入学习焦虑到明确目标,决心通过项目实践提升技术能力的转变过程。文章核心在于提出“以前端为根基,具备全栈交付能力,并能借助AI提高研发效率和产品能力的工程师”这一目标,并详细规划了学习路线,包…

📅 2026/10/7 9:01:21
终极免费窗口强制调整工具:5个技巧突破Windows尺寸限制

终极免费窗口强制调整工具:5个技巧突破Windows尺寸限制

终极免费窗口强制调整工具:5个技巧突破Windows尺寸限制 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 你是否经常遇到那些无法拖拽的"顽固窗口"&#xff1f…

📅 2026/10/8 3:49:01
MORE NEWS

更多资讯

📰

Agentic RAG深度研究实战:架构共性、证据核验与效率边界

过去半年我在 Agent 论文和工业落地之间来回横跳,最深的感受是:Agentic RAG 和深度研究这两个词已经被用到快没有边界了。搜索引擎、企业知识库、论文总结工具,全都往“深度研究”上靠,但真正能打通“检索 → 证据核验 → 长程任务…

📰

全自动UV平板打印机SW16可编辑模型二次开发与参数化改造实战

简介:这份资源是面向机械设计与机电自动化从业者的SW16全自动UV平板打印机三维模型包,适合需要研究UV固化打印设备结构、进行非标设备仿制或二次开发的中高级工程师。压缩包共250个文件,约108.95MB,以218个sldprt零件模型和30个sl…

📰

AI智能体开发标准化流程与最佳实践

1. AI智能体开发的核心挑战与标准化需求过去三年里,我参与了17个不同行业的AI智能体项目,从电商客服到工业质检,最深的体会是:90%的失败案例都源于开发流程的混乱。有个医疗问诊项目,团队花了三个月训练出准确率95%的模…

📰

C++异常处理机制原理与性能优化实践

1. C异常捕获机制深度解析1.1 异常处理的基本原理C异常处理机制本质上是一种非本地控制流转移机制。当throw语句被执行时,程序会立即终止当前函数的执行,并开始沿着调用栈向上查找匹配的catch块。这个过程被称为栈展开(stack unwinding&#…

📰

Vue3深色主题实现与优化实践

1. 为什么深色主题成为现代Web应用的标配?在2023年的Web开发领域,深色主题(Dark Mode)已经从"锦上添花"变成了"必不可少"的功能需求。根据最新的用户体验调研,超过82%的用户会在支持深色主题的应用…

📰

游标分页技术解析:解决百万级数据深分页性能问题

1. 深分页的痛点与常见误区当数据量达到百万级时,传统的LIMIT OFFSET分页方式就会暴露出严重的性能问题。我曾在处理用户行为日志时,遇到过这样一个案例:一个简单的分页查询SELECT * FROM user_logs ORDER BY id LIMIT 10 OFFSET 1000000&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬