深耕政务信息化 20 年,这套自研 Java Web 框架支撑了省级新农保、全国跨省医保结算等核心民生系统,稳定运行 18 年。本复盘不讲空泛理论,只聚焦真实生产环境下的架构决策、踩坑经历与落地方案,不求优雅,但求能跑、能扛、能维护。
在长期维护政务系统的过程中,逐渐形成一套轻量、稳定、无侵入、可长期演进的架构思路。这套框架没有依赖流行全家桶,而是围绕业务痛点一点点打磨,最终支撑了海量高并发、高可靠的民生业务。核心决策主要围绕以下十个方面展开:
- 放弃 Spring,手写轻量 IOC 容器:通过自定义注解
@bean、@property、@responseMapping配合BeanFactory,搞定实例化、注入与路由注册,适用于部署环境受限场景。 - 注解路由 + 参数路由,实现新老代码平滑迁移:在路由分发逻辑中先走注解路由,找不到再走老的
Business/Action参数路由,确保系统迭代升级时不中断服务。 - 统一入参解析,前后端彻底解耦:根据方法签名自动转换参数类型,DataCenter、Dao、List、HttpServletRequest 都能自动识别,前端统一 POST JSON,后端方法签名随意定义。
- CGLIB + 责任链实现轻量 AOP:利用
doProxy+proxyFilter+ 责任链模式,通过@Trans、@Logger、@monitoring注解即可处理事务、日志与监控,横切关注点不侵入业务代码。 - ASM 字节码直读,100% 获取方法参数名:使用 ASM 直接读取 class 文件字节码,从 LocalVariableTable 获取参数名,解决编译时不加
-parameters也能拿到真实参数名的痛点。 - ThreadLocal 上下文管理,业务层彻底告别 Http:继承 ThreadLocal 的
AppContextContainer在 Servlet 层绑定用户、连接等信息,业务层随时取用,不再依赖 Servlet API。 - MongoDB 混合存储,零侵入提升查询性能:在 Dao 上配置
level属性(1=双写、2=纯 MongoDB+ 异步同步、3=纯关系库),由DBUtil自动路由,无需引入 Redis/MQ 也能抗住缓存需求。 - 修改 MyBatis 源码 1 行,搞定 Oracle 物理分页:PaginationInterceptor 用绑定变量
?做分页而非拼接 SQL,配合 OracleDialect/MSsqlDialect 方言,避开硬解析大坑。 - Excel 模板驱动政务报表,业务人员直接改格式:一个 Servlet 通吃所有报表,Excel 文件即模板,jxl 读数据转 PDF 预览,解决报表格式频繁变动导致开发反复改代码的问题。
- Activiti 工作流任意跳转、回退:运行时动态修改流程定义的连线,跳转到任意节点,完成后恢复原状,满足政务审批需要自由跳转、回退、转办的灵活场景。
框架全景图
┌─────────────────────────────────────────────────────────┐
│ 前端层 │
│ browise RIA 框架(基于 Dojo 封装) │
│ DataCenter / DataStore / JSON 序列化 │
└──────────────────────────┬──────────────────────────────┘
│ POST JSON
┌──────────────────────────▼──────────────────────────────┐
│ route.java(唯一 Servlet) │
│ ┌──────────────┬──────────────┬──────────────┐ │
│ │ 登录校验 │ 路由分发 │ 异常处理 │ │
│ └──────────────┴──────────────┴──────────────┘ │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ BeanFactory(IOC 容器) │
│ @bean 实例化 @property 注入 @aoppoint 代理 │
│ CGLIB 代理 + 责任链模式 │
│ @Trans 事务 @Logger 日志 @monitoring 监控 │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ 业务层(@responseMapping 路由) │
│ Control → Service → Mapper(MyBatis) │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ DBUtil(ORM 层) │
│ ┌──────────────┬──────────────┬──────────────┐ │
│ │ MyBatis │ MongoDB 缓存 │ 通用查询 │ │
│ │ CRUD │ level 1/2/3 │ JDBC 方式写文件│ │
│ └──────────────┴──────────────┴──────────────┘ │
│ ┌──────────────┬──────────────┐ │
│ │ SM4 加解密 │ AWR 报告解读 │ │
│ │ @myCode │ JVM 监控 │ │
│ └──────────────┴──────────────┘ │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ 数据库(Oracle / MongoDB) │
└─────────────────────────────────────────────────────────┘
十个决策的统一原则
| 决策 | 原则 |
|---|---|
| 自研 IOC | 只加需要的不加不需要的 |
| 注解路由 + 参数兼容 | 不破坏老系统 |
| 统一入参解析 | 前后端解耦 |
| CGLIB + AOP | 加注解的方式 |
| ASM 参数读取 | 自己的问题自己解决 |
| ThreadLocal 上下文 | 业务层不依赖 Servlet |
| MongoDB 混合存储 | 零侵入,渐进式采用 |
| 改 MyBatis 源码分页 | 第一天解决的事用了十几年 |
| Excel 模板报表 | 用业务人员熟悉的工具 |
| Activiti 任意流转 | 不能改变框架时就找到"洞"绕过去 |
一句话:做到实时有据,修改即刻可查。
不追求架构漂亮,不追求技术先进,只追求出了问题我能从代码快速定位到业务,业务人员能快速进入查到数据。这个框架没有 Spring 的依赖注入,没有 MyBatis-Plus 的包装,但这是它的一个优点:每一行代码我都能说清来龙去脉,任何问题我都能从入口一步步追踪到数据库。


