前、策、工、代——四个设计模式撑起一个政务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多个模式的定义是先写足够多的代码然后在自己的代码里认出那些反复出现的结构。认出来一次这个模式就再也不会忘了。