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. MySQL视图更新

    昨天在写美团2019秋招笔试题的时候遇到了关于视图是否能更新的问题,突然感觉这个问题之前复习的时候重点关注过,但是却又想不全.今天特地搜了一些资料总结一下.本文主要说明视图的更新限制,如需关于视图的更 ...

  2. extremecomponents

    具体教程: http://www.cnblogs.com/QQParadise/articles/1488920.html 教程中涉及到springmvc的相关知识 下载地址:http://sourc ...

  3. 【高并发架构】Redis缓存高并发之-主从架构

    Redis主从架构 到目前为止,Redis Cluster 能实现很好的性能,但如果只是缓存几个G的数据,那么单机Redis就足够了,但缓存主要用来读的,单机的QPS有一定的极限,一两万QPS一台应该 ...

  4. Mysql 创建及导入表

    连接数据库 打开命令行输入mysql -uroot -p 进行数据库连接 创建并访问数据库 CREATE DATABASE test: //创建数据库test SHOW DATABSAES; //查看 ...

  5. JSP的执行原理

    在一个JSP文件第一次被请求时,JSP引擎把该JSP文件转换成为一个Servlet.而这个引擎本身也是一个Servlet.JSP的运行过程如下所示: (1)JSP引擎先把该JSP文件转换成一个Java ...

  6. 【RL-TCPnet网络教程】第9章 RL-TCPnet网络协议栈移植(uCOS-III)

    第9章        RL-TCPnet网络协议栈移植(uCOS-III) 本章教程为大家讲解RL-TCPnet网络协议栈的uCOS-III操作系统移植方式,学习了第6章讲解的底层驱动接口函数之后,移 ...

  7. #Java学习之路——基础阶段(第八篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...

  8. [SQL]LeetCode196. 删除重复的电子邮箱 | Delete Duplicate Emails

    Write a SQL query to delete all duplicate email entries in a table named Person, keeping only unique ...

  9. [Swift]LeetCode868. 二进制间距 | Binary Gap

    Given a positive integer N, find and return the longest distance between two consecutive 1's in the ...

  10. 非对称加密技术里面,最近出现了一种奇葩的密钥生成技术,iFace人脸密钥技术

    要说到非对称加密技术啊,得先说说对称加密技术 什么是对称加密技术 对称加密采用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥加密. 也就是密钥也可以用作解密密钥,这种方法在密码学中叫做对称 ...