1、背景:

  公司基础设施部门推出了自己的微服务框架(以下简称M),要求所有业务应用都要接入进去,但坑爹的是M只提供了SpringMVC工程的support,对于采用Stripes作为MVC框架的应用并不支持,所以就必须重构这个Stripes应用。

  M虽然代替Tomcat自己实现了IO,工作线程池,服务注册发现等等,但还是提供了对Servlet规范的简单支持(移除了web.xml,filter,listener, 打包方式也改成了tar.gz,保留了ServletContext,request,response等等)。

2、思路与分析:

  由于现有应用的业务逻辑还是比较复杂(沉淀了3,4年),且涉及到多个APP端和其他第三方的交互,所以如果想对应用做完全的重构是一件非常头痛的事情,不仅要投入大量的后端,测试等人力成本,而且整个重构周期也会比较长,影响到对其他需求的响应。

  于是在想:既然SpringMVC和Stripes都遵循Servlet规范,而M又能支持SpringMVC,是否可以通过SpringMVC拦截到所有请求后,把之前的老接口的请求转发给Stripes处理,以后新开发的接口就直接走SpringMVC,这样既兼容了公司的M框架也对原有应用的改动较小,开发周期短,测试人员只需要验证一些系统边界和主要流程,不用再挨个挨个验证已有的业务逻辑,这样可以节省大量人力成本,缩短开发周期。

  SpringMVC是目前最流行的MVC框架,是Spring庞大家族的一员,而Stripes也是一个非常轻量的MVC框架,但是SpringMVC的Controller跟Stripes的ActionBean有个很明显的区别就是前者是单例的,跟状态无关,所有的请求参数都是封装在ServletRequest中的,而后者是prototype,每次请求都会重新生成一个ActionBean对象。

  Spring有很强的可扩展性,SpringMVC也不例外,下面简单列了一下扩展的几个思路:

  1.扩展mvc名称空间:扩展RequestMappingHandlerAdapter等
    优点是:可以将整个请求的处理流程纳入到SpringMVC
    缺点是:侵入性较大,SpringMVC版本升级后需要再做适配,技术实现比较麻烦

  2.扩展DispatcherServlet:重写onRefresh或者doService等
         M的spring-support是直接创建DispatcherServlet的,需要M的同事开回调入口,不太现实

  3.增加拦截器,没有侵入性,不影响后续SpringMVC升级版本等
      缺点是扩展性不是很好,不过对桥接需求来说已经完全足够

  4.自定义Handlermapping,没有侵入性,理论上可以保证现有拦截器不需要改造,
        但是会导致SpringMVC的拦截器和Stripes的拦截器定义两套,后期维护麻烦(两个地方都需要修改)

       经过对比和讨论,我选择了第三点,新增一个SpringMVC拦截器,下图是一个简单的流程示意图:

3、动手实现原型:

新建桥接工程XXX-bridge,所有新增代码均放在新工程,对老工程零侵入(老板特别强调,如果桥接失败了,一定不能影响现在核心工程,要能马上回退回去),所以老工程仅新增了pom文件里的两个plugin,可以实现Stripes和SpringMVC两种框架模式下的并行开发,(原来的老工程持续有需求进来)。

    /**
* 拦截所有请求,如果能映射到Stripes则直接派发给Stripes并return false,如果不能映射则回退给SpringMVC
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
if (handlerMapping.isEmpty()) {
return true;
}
String url = httpServletRequest.getRequestURI();
String contextPath = httpServletRequest.getContextPath();
url = url.replace(contextPath, "").replaceAll("/+", "/");
LOGGER.info("当前请求路径: {}", url);
if (!StripesContextHandlerInterceptor.handlerMapping.containsKey(url)) {
LOGGER.info("请求由SpringMVC处理: {}", url);
return true;
}
try {
LOGGER.info("请求由Stripes处理: {}", url);
StripesContextHolder.doService(httpServletRequest.getServletContext(), getApplicationContext(),
httpServletRequest, httpServletResponse);
return false;
} catch (Exception e) {
LOGGER.error("处理请求异常:", e);
return false;
}
}

关键点在于要解析到所有的老接口地址,然后通过拦截器来判断当前请求是否是老接口,是的话就转发给Stripes来处理,其他详细的代码托管在github,欢迎访问。

https://github.com/hiccup234/web-advance/tree/master/bridge

4、问题与验证:

1、因为初始化Stripes需要 ServletContext,但是应用启动时却没办法获取到 ServletContext 对象,所以在 StripesContextHolder 里做了懒加载,只有当第一个请求进来后才加载和初始化Stripes框架。

  2、Stripes是可以支持queryString为空的查询的,类似:http://127.0.0.1/server/test?list  而M会在解析请求参数的时候对这种情况直接抛异常,经过与基础设施同事协商,他们做出让步,对这种请求的情况直接放行给应用,从而避免了前端和第三方做改造。

  今晚上线成功,目前跟Tomcat并行发布,5%的流量灰度,观察日志一切正常。前期的技术验证加上近两周的开发联调到今天的上线,算是向着架构的方向迈出了小小一步(同时:也感谢测试同学的自动化,让验证和回归省去了很多工作量)

拯救老旧工程,记桥接SpringMVC与Stripes框架的更多相关文章

  1. 老的工程移植到AndroidStudio需要修改的注意事项

    之前老的工程用android-apt编译,如果要在新的AndroidStudio编译至少需要修改一下几部分: 1. 修改project里的build.gradle dependencies { cla ...

  2. HomeKit 与老旧设备

    苹果推了HomeKit,已经有很多厂商在做,可以达到Siri控制所有设备的功能. 但是Siri也不是万能的,对人类的语义理解也会产生差错,不过我相信未来这个问题会解决掉.     如果家里有老旧的电视 ...

  3. 7款适用老旧设备并对初学者非常友好的轻量级Linux发行版

    我们由从 7 到 1 的顺序向大家介绍. 7. Linux Lite 正如其名,Linux Lite 是 Linux 发行版的一个轻量级版本,用户并不需要强大的硬件就可以将它跑起来,而且其使用非常简单 ...

  4. Vivado2016旧工程IP移动到新工程

    前言 在VIVADO中图形化界面生成IP,在旧工程中使用后,如果想在新的工程中使用这个IP但又不想再次生成一次,则就需要把就旧工程中的IP导入到新工程中. 流程 1.旧工程IP生成的目录如下,IP为C ...

  5. Angular 学习笔记 ( 创建 library, 转换老旧的 library )

    更新 : 2018-10-28 不知道为什么在 ng 跑一直做不到 .d.ts 最后发现,如果有一个插件 propagating-hammerjs.ts 那么就在 root create 一个 pro ...

  6. 用mongodb 固定集合实现只保留固定数量的记录,自动淘汰老旧数据

    在一个保存report记录的场景中,我们使用MongoDB进行数据存储 example: db: report Collection: daily_report 创建db:  use report; ...

  7. CentOS7清理老旧内核

    CentOS7如果是一步步内核升级上来的将会面临一个问题(一般安装了图形化界面的系统常见),由于内核增多/boot/的容量减少,导致启动变慢.这时就需要清理老旧内核,释放/boot/空间. 使用una ...

  8. 手把手Maven搭建SpringMVC+Spring+MyBatis框架(超级详细版)

    手把手Maven搭建SpringMVC+Spring+MyBatis框架(超级详细版) SSM(Spring+SpringMVC+Mybatis),目前较为主流的企业级架构方案.标准的MVC设计模式, ...

  9. Springmvc整合tiles框架简单入门示例(maven)

    Springmvc整合tiles框架简单入门示例(maven) 本教程基于Springmvc,spring mvc和maven怎么弄就不具体说了,这边就只简单说tiles框架的整合. 先贴上源码(免积 ...

随机推荐

  1. Python连接MySQL数据库之pymysql模块使用

    安装PyMySQL pip install pymysql PyMySQL介绍 PyMySQL是在python3.x版本中用于连接MySQL服务器的一个库,2中则使用mysqldb. Django中也 ...

  2. [.net 面向对象程序设计深入](31)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)

    [.net 面向对象程序设计深入](31)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...

  3. Redis 设计与实现 (四)--事件、客户端

    事件 一.文件事件 文件事件处理器使用I/O多路复用程序来同时监听多个套接字, 监听套接字,分配对应的处理事件. 四个组成部分:套接字 .I/O多路复用 . 文件事件分派器 . 事件处理器 连接应答处 ...

  4. Java引入的一些新特性

    Java引入的一些新特性 Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本. Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程, ...

  5. Python档案袋( Socket 与 ScoketServer 通信 )

    Socket有一个缓冲区,缓冲区是一个流,先进先出,发送和取出的可自定义大小的,如果取出的数据未取完缓冲区,则可能存在数据怠慢.其中[recv(1024)]表示从缓冲区里取最大为1024个字节,但实际 ...

  6. Kafka对Java程序员有多重要?连阿里都再用它处理亿万级数据统计

    一.了解淘宝Kafka架构 在ActiveMQ.RabbitMQ.RocketMQ.Kafka消息中间件之间,我们为什么要选择Kafka?下面详细介绍一下,2012年9月份我在支付宝做余额宝研发,20 ...

  7. Spring设计模式_工厂模式

    先说下工厂模式的特性 1.对于调用者来说,影藏了复杂的逻辑处理过程,调用者只关心执行结果. 2.工厂要对结果负责,保证生产出符合规范的产品. Git代码地址  https://github.com/w ...

  8. oracle 12C利用dbca建库13步

    oracle用户登录然后命令行执行:dbca 如果没有此命令可以用:find / -name "dbca"查到后执行. 1.选择Create a database 2.选择Adva ...

  9. Android Studio 获取数字签名

    下面介绍下调试版本和发布版本,获取数字签名的方法,通过以下方法可以获取到SHA1和MD5 1.调试版本 在调试模式下,Android studio会默认生成一个debug.keystore签名文件,因 ...

  10. 用Javascript方式实现LeetCode中的算法(更新中)

    前一段时间抽空去参加面试,面试官一开始让我做一道题,他看完之后,让我回答一下这个题的时间复杂度并优化一下,当时的我虽然明白什么是时间复杂度,但不知道是怎么计算的,一开局出师不利,然后没然后了,有一次我 ...