百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

当我接到一个DAU几十w的项目,并开始维护它

lipiwang 2024-10-31 15:24 18 浏览 0 评论

最近,我着手维护一个项目,在原来代码的基础上去做开发、维护的工作。这个项目曾经承载着日活几十万,月流水一个多亿的业务,所以它里面一定会有很多的功能和优秀的思想。

我拿到源代码的时候给我的是一个zip包,它就像一个黑盒子,承载着你所有的期待和不确定性,没有任何人去告诉我这个项目里都有什么业务,它是什么样子的一个架构,它应该怎么启动,启动之后应该怎么访问,都有哪些接口,更没有任何项目文档,连数据库里的表结构都没有注释。

当我把它解压之后,我发现这是一个单体maven项目,看起来应该不错,至少不是一个老古董(还记得在lib目录下手动添加三方依赖jar包解决冲突的时代吗?)。

我需要快速去熟悉它,并在此基础上开发新的功能。

实际工作中,你们遇到过这种项目吗?你是如何进入并逐步熟悉它呢?以下分享我的一些方法。

1、项目概览

当我用idea打开它的时候,光是依赖我就下载了一个多小时,可能是我的网络不好,但至少可以确定的是,内网的maven私服仓库里没有这些版本的jar包。

我在下载依赖的过程中,扫了一眼pom.xml文件,竟然发现了struts2的依赖,是被注释掉的:

还记得这些struts2的依赖包都是干嘛的吗?

继续去查看关于spring框架的依赖,我想它一定是有的,否则离开了spring框架,我肯定玩不转它,看到了spring的依赖,是基于4.2.1.RELEASE版本的:

<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.2.1.RELEASE</spring.version>
</properties>

可以知道的是,这不是一个springboot项目,更不可能是springcloud项目了,这个项目曾经来自于SSM或者SSH的架构,这里的第一个S可不是SpringMVC,是Struts2,相信没有五年工作经验的人,大多数没有用过这个框架,除非你和我一样接手了一个古董项目。

终于下载完项目依赖,可以看到这个项目的全貌了。

它是一个标准的java web项目,有src/main/java、resources、webapp,webapp下面还有WEB-INF目录,以及web.xml。

大家都知道,一个标准的基于springboot前后端分离的项目是没有webapp和web.xml文件的,这些都被springboot通过注解给干掉了。

还记得web的三大组件吗?

Servlet、Listener、Filter,这些都属于web基础,一定要会的。

用springboot的同学也要知道springboot里是怎么玩这三大组件的。

到这里我开始感到惊讶了,一个月流水过亿、日活几十万、研发团队几十号人,项目竟会如此老旧?还是传统的单体应用,以war包方式部署?你们的技术追求呢?

在微服务满天飞的今天,大家是不是觉得不可思议?

是的,可是他就这样存在着,而无视单体应用带来的部署风险、代码冲突导致的效率低下。

2、先把它运行起来

显然它不是一个springboot项目,也没有看到启动类,所以我需要一个web容器来把这个war包部署运行起来。

如果他能够在本地tomcat下运行起来,说明他是完整的、健康的,反之我需要解决导致无法启动的问题,在一切还没有熟悉的时候。

显然,我没有把它运行起来,根据启动日志发现是无法连接memcached,可是我并不准备使用memcached,这就需要我去了解是否能够使用redis去替换掉它。从技术角度来看是可以的,比较memcached只有字符串类型,只要保证序列化和反序列化工具不变就行。

开始进入这个项目的代码世界了,果不其然,代码是15年的代码,有点老旧,和我的工作年限差不多。

发现memcached的使用被封装成了一个类,这还不错,至少不用到处修改,此时我只需要搞清楚一个问题,有没有一些初始化的数据放在memcached中,如果没有就可以放心的替换掉memcached了,如果有,那么就需要拿过来放到redis一份。

但是这个问题是没有人告诉我的,也没有任何文档,原来的阿里云memcached服务器也被释放了,所以忽略这个问题。

开始更改这个类,使用RedisTemplate来替换原来的MemcachedClient,因为这个类里的方法都是static修饰的,所以我想使用@Resource的方式注入RedisTemplate行不通,只能定义一个全局静态变量,来拿到RedisTemplate这个bean。

所以我不得不写一个工具类来获取自己想要的任何bean:

还记得Spring中的接口类ApplicationContextAware的作用吗?

XxxAware就是对xxx感知的意思,这里就是对ApplicationContext感知的意思,实现这个接口可以拿到ApplicationContext,然后通过它可以获取到很多我们想要的东西,比如容器中加载的bean,environment等。

当然这个类我还需要加载到容器中去,因为框架的原因,我不得不使用xml的bean定义方式:

<bean id="springUtil" class="com.xxx.SpringUtil" lazy-init="false"/>

知道这里为什么是lazy-init=false吗?

这个时候我就可以通过这个SpringUtil工具类来获取我们想要的redisTemplate实例bean对象了:

private static RedisTemplate redisTemplate = SpringUtil.get("redisTemplate",RedisTemplate.class);

第一个麻烦解决了,继续使用tomcat来运行它,这个时候发现了一个诡异的问题,日志没有任何问题,就是运行到一半卡住不动了,我以为是我刚刚修改的代码有问题,会不会是SpringUtil这个类加载的时候有死循环之类的问题,使用top命令查看,没有吃cpu很厉害的线程,java相关的线程cpu也很稳定,那就一定是阻塞在什么地方了。

重新启动一下试试,还是这个问题,卡住不动,但是我发现了一个问题,每次日志都在一个地方卡住就不再输出了,找到这行日志在代码中的位置,发现是阿里云的OSSClient连接问题,进而发现开发环境连接地址竟然是阿里云oss的内网地址。

换成外网地址继续启动,这次终于启动成功。

3、去找一个业务点作为突破口

当项目成功启动之后,我试图去找一个controller作为入口逐步跟进去,看都做了什么事情以及怎么做的,可是我并没有找到这个项目的任何Controller,而是发现了一个servlet的package,里面有大量的子package和servlet,我开始有预感,这是一个用servlet来开发API层的项目,而不是@Controller、@RestController类型的,当我打开其中一个HomeServlet,我看到代码注释说这是一个商城首页的Servlet,并且开发时间是15年3月:

看这段代码,是基于@WebServlet注解来实现的,注入的方式是用servlet的init()方法来注入相关的service,数据传参处理也没有SpringMVC的@RequestParam、@RequestBody这样的注解来封装,所以传参、参数的校验、数据的返回处理都需要自己写代码来处理。

继续跟进到service层,发现了一个巨大的方法,244行代码:

且返回也没用对象封装,而是一个万能的HashMap<String, Object>,哎,一群没有技术追求的同学。。。

dao层发现用的是ibatis,dao层就不用跟了,没有什么业务,无非就是一些sql,能支持事务就行。

项目的整体脉络已经摸的差不多了,接下来就是梳理这里的业务,将项目整体分成几大模块,不求甚解,整体把握即可。

4、后面要做的事情

基于这样的一个项目,大家有没有一些改造的想法?如果给你这个项目,在保证业务ok的情况下,你有哪些想做的事情?

秉持做事的态度,为了以后开发维护方便,我觉得我还是需要去做一些事情的,例如这些:

  1. 将SpringMVC集成进来,使得SpringMVC和当前的Servlet两种可以共存,新的用SpringMVC开发,旧的逐步改造过来,集成的时候考虑版本的兼容问题;
  2. 抽一个公共返回类,比如ResultResp<T>,并提供一些success(),success(T data),fail(),fail(int code, String msg)方法,用于接口统一返回;
  3. 统一的异常拦截处理,不吐服务端异常信息给前端;
  4. 重构一些业务模块,使得每个方法不超过80行,方法的复杂度不超过18,多加注释;
  5. 一些重复的代码功能采用注解的形式抽取出来;
  6. 将service层的sql语句下沉到dao层;
  7. 后期择机将一些相对独立的模块抽取出来形成特定的服务;
  8. 不再以war包的形式部署,整包部署风险太高,降低粒度到class文件,采用Git版本控制增量部署、指定tag回滚;
  9. 因为是单体应用,目前还不需要链路跟踪,但是类似于ELK的日志收集、监控工具还是需要的;
  10. 写一个alarm报警微服务,一旦产生error级别的日志,或者产生RuntimeException则实时报警到钉钉群,谁让我维护的是一个日活几十万、月流水过亿的项目呢?

暂且就这些吧,后续根据项目的进展情况再逐步迭代。

相关推荐

一个简单便捷搭建个人知识库的开源项目(MDwiki)

这里我通过自动翻译软件,搬运总结MDwiki官网的部署和使用方法。第一步:下载编译好的后MDwiki文件,只有一个HTML文件“mdwiki.html”。第二步:在mdwiki.html同级目录创建“...

强大、简洁、快速、持续更新 PandaWiki新一代 AI 驱动的开源知识库

PandaWiki是什么PandaWiki是一款AI大模型驱动的开源知识库搭建系统,帮助你快速构建智能化的产品文档、技术文档、FAQ、博客系统,借助大模型的力量为你提供AI创作、AI问答...

DeepWiki-Open: 开源版Deepwiki,可自己构建github文档库

Deepwiki是Devin团队开发的github文档库,用户能免费使用,但代码不是开源,而DeepWiki-Open侧是开源版本的实现。DeepWiki-Open旨在为GitHub和GitLa...

最近爆火的wiki知识管理开源项目PandaWiki

项目介绍PandaWiki是一款AI大模型驱动的开源知识库搭建系统,帮助你快速构建智能化的产品文档、技术文档、FAQ、博客系统,借助大模型的力量为你提供AI创作、AI问答、AI搜索等...

轻量级开源wiki系统介绍(轻量开源论坛系统)

wiki系统有很多DokuWiki、MediaWiki、MinDoc等等都是开源的wiki系统。商业版的wiki,像很多企业在用的confluence等。今天我们讲的是一款轻量级且开源的文档管理系统:...

DNS解析错误要怎么处理(dns解析状态异常怎么办)

在互联网时代,网络已经成为人们生活和工作中不可或缺的一部分。然而,当遇到DNS解析错误时,原本畅通无阻的网络访问会突然陷入困境,让人感到十分困扰。DNS,即域名系统,它如同互联网的电话簿,将人们易于...

网页加载慢?这些方法让你秒开网页!

打开浏览器,信心满满地准备查资料、看视频或者追剧,却发现网页怎么都打不开!是不是瞬间感觉手足无措?别慌,这个问题其实挺常见,而且解决起来并没有你想象的那么复杂。今天就来聊聊网页打不开究竟是怎么回事,以...

windows11 常用CMD命令大全(windows11msdn)

Windows11中的命令提示符(CMD)是一个强大的工具,可以通过命令行执行各种系统操作和管理任务。以下是一些常用的CMD命令,按功能分类整理,供你参考:一、系统信息与状态systeminfo显...

电脑提示DNS服务器未响应怎么解决?

我们在使用电脑的时候经常会遇到各种各样的网络问题,例如最近就有Win11电脑用户在使用的时候遇到了DNS未响应的问题,遇到这种情况我们应该怎么解决呢?  方法一:刷新DNS缓存  1、打开运行(W...

宽带拨号错误 651 全解析:故障定位与修复方案

在使用PPPoE拨号连接互联网时,错误651提示「调制解调器或其他连接设备报告错误」,通常表明从用户终端到运营商机房的链路中存在异常。以下从硬件、系统、网络三层维度展开排查:一、故障成因分类图...

如何正确清除 DNS 缓存吗?(解决你访问延时 )

DNS缓存是一个临时数据库,用于存储有关以前的DNS查找的信息。换句话说,每当你访问网站时,你的操作系统和网络浏览器都会保留该域和相应IP地址的记录。这消除了对远程DNS服务器重复查询的...

网络配置命令:ipconfig和ifconfig,两者有啥区别?

在计算机网络的世界里,网络接口就像是连接你电脑和外部网络的桥梁,而网络配置则是确保这座桥梁稳固、通信顺畅的关键。提到网络配置工具,ipconfig和ifconfig绝对是两个绕不开的名字。它们一...

救急的命令 你会几个?(救急一下)

很多人都说小编是注册表狂魔,其实不完全是,小编常用的命令行才是重点。其实所谓的命令行都是当初DOS时代的标准操作方式,随着Windows不断演化,DOS的命令早已成为Windows的一部分了——开始菜...

电脑有网却访问不了GitHub原来是这样

当满心欢喜打开电脑,准备在GitHub这个“开源宝藏库”里挖掘点超酷的项目,却遭遇了网页无法访问的尴尬。看着屏幕上那令人无奈的提示,原本高涨的热情瞬间被泼了一盆冷水,是不是感觉世界都不美好了...

rockstargames更新慢| r星更新速度 怎么办 解决办法

rockstargames更新慢|r星更新速度怎么办解决办法说到RockstarGames,那可是游戏界的大佬,作品个顶个的经典。但话说回来,每当新内容更新时,那蜗牛般的下载速度,真是让人急得...

取消回复欢迎 发表评论: