Java项目信创改造实践指南:从环境适配到数据库迁移的完整路线
做信创改造,这几个字从刚听到时的陌生到现在成为项目立项书里的固定条目,我算是完整走过了好几个Java项目的全程。所谓信创,落到工程上就是一句话:把你跑在Intel+CentOS+Oracle+Tomcat这一链条上的系统,换到鲲鹏/飞腾、麒麟/UOS、达梦/金仓、东方通/宝兰德这些国产软硬件上,而且还得保证功能、性能、稳定性不打折。Java项目在信创赛道上有着天然优势,因为JVM帮你把硬件的差异屏蔽掉了大半,但这绝对不意味着把包拷过去就能跑。
这篇内容写给正在接信创改造任务的Java开发、架构师和实施人员。我会按我实际操盘过的项目顺序,把环境适配、中间件替换、数据库迁移、代码层修复这几个环节里的细节和坑都摆出来。尤其是那些从Oracle迁移到国产库的老系统,SQL方言、驱动类加载、JNI本地库、字符集、国密算法,哪一个冒出来都够你熬几个通宵。读完你至少能排出一份可落地的改造路线图,知道每个阶段该验证什么、在哪里最容易翻车。
1. 信创改造到底要改什么
1.1 先盘清家底:你的系统依赖了什么
改造之前最忌讳的事情就是直接开干。信创涉及整条技术栈的替换,如果你连当前系统到底跑在什么环境都不清楚,后面每一层都会出问题。我每次进项目做的第一件事,是拉着运维一起把下面的清单拉出来,而且要跟线上环境逐一核对,不能只看文档:
- 硬件层:CPU架构是x86_64还是ARM,核心数、内存大小。别小看这个,后面JDK参数、数据库连接池、中间件native库全依赖它。
- 操作系统层:当前发行版及版本,内核版本,系统locale设置,是否开启了SELinux或防火墙策略。
- Java运行时:JDK是Oracle还是OpenJDK,具体小版本,用的是JRE还是完整JDK,JVM参数在哪配置。
- 应用服务器:Tomcat/WebLogic/JBoss,版本、启动参数、部署方式、集群模式。
- 数据库:产品与版本、表数量、总数据量、是否用了存储过程、触发器、作业调度、全文索引、序列等高级特性。
- 中间件与基础组件:Redis、Nginx、RabbitMQ、Kafka、ElasticSearch等,各自版本和集群方式。
- 代码里隐藏的平台依赖:项目是否引入JNI/JNA本地库,是否生成PDF/图片/Excel,是否调用系统命令,是否依赖特定字体。
- 客户端侧:浏览器内核要求,是否依赖ActiveX、Applet,是否有桌面端组件。
一次真实项目的教训:台账上写的是CentOS 7.6 + Oracle JDK 1.7,结果生产环境实际是麒麟系统 + 一个老掉牙的解压版JDK,并且JSP编译都过不去。如果前期调研不做到这个粒度,改造范围和工作量评估就是空中楼阁。
盘完之后我的经验是,一个典型的Java业务系统做信创改造,工作量分布大概是:数据库适配占四成,运行时环境适配占三成,代码层兼容性修复占据两成,剩余是测试验收与协调时间。很多人以为改代码才是大头,实际上代码层面的坑反而比较集中,数据库和环境的适配才是真正消磨精力的地方。
1.2 Java在信创赛道里的天然优势与隐性问题
Java能成为信创改造里相对省心的语言,核心功劳要记在JVM头上。JVM帮你把CPU架构和操作系统的差异挡掉了大部分,同一个jar包在x86的CentOS上能跑,换到ARM架构的麒麟系统上大概率也能跑,前提是两件事:JDK本身支持这个平台,你的项目里没有平台相关的本地代码。
但隐性问题也真实存在,我在改造中遇到过好几类,这里展开讲一讲。
第一类,JNI/JNA调用本地库。这是最致命的。一个老项目如果要调用底层的加解密so库、身份证读卡器DLL的Linux版、或者某个厂商的人脸识别SDK,CPU架构一旦变了,这些二进制库基本全部失效。ARM架构需要重新编译,但很多厂商根本没有ARM版的库,你只能回到厂商那要适配版,或者把这块功能用Java重写。有一个比较现实的判断标准:如果项目出现了Native.loadLibrary或者System.load这行代码,务必在需求阶段就去确认本地库的跨平台支持情况。
第二类,字体与图形渲染。很多业务系统都有验证码、二维码、PDF导出、Excel图表功能,这些看起来是纯Java的处理,底层却会调用操作系统的字体库。信创操作系统默认安装的字体和Windows、CentOS下并不完全一样,最常见的结果就是PDF导出后中文全部变方框,或者图片验证码渲染出来全是乱码。这个坑几乎每个项目都会踩,但注意提前验证,解决方案也简单:在测试环境安装中文字体包,或者打包字体文件随应用一起发布。
第三类,JDK版本的软差异。信创环境普遍使用OpenJDK,或者厂商定制JDK,比如华为毕昇JDK、龙芯JDK。从Oracle JDK迁过来,大多数业务代码没有问题,但如果代码用到了com.sun.*内部类,或者依赖了只有Oracle JDK特有的工具和参数,就必须排查。用jdeps工具对项目打出的所有jar包做一次依赖分析,是最稳妥的办法,后面我会细说这个工具怎么用。
第四类,硬编码外部资源。老项目最容易在配置文件甚至代码常量里写死数据库IP、文件服务器路径、加密参数。信创环境一换,这些值全都对不上,而且报错非常难查。建议在迁移阶段就对全局配置做一次扫描,把环境相关的配置全部外置到Nacos或配置中心。
2. 运行时环境适配:从CPU到操作系统的第一层考验
2.1 硬件架构与操作系统选型
信创硬件平台主流有多个方向:华为鲲鹏和飞腾属于ARM架构,海光和兆芯是x86架构,龙芯是自主指令集。对Java项目来说,平台选择直接影响改造成本。如果你原来就是Intel服务器,换成海光或者兆芯的x86平台,兼容性成本最低,很多在CentOS上编译的二进制可以直接跑。如果选择鲲鹏或飞腾的ARM平台,那么所有配套组件都必须有ARM版本,包括但不限于Nginx二进制、Redis、Tomcat native库、各种Agent监控组件。
操作系统方面,政企项目里最常见的两个方向是麒麟和统信UOS,这两个都有服务器版。实践经验来看,它们都是Linux内核派系,命令风格、包管理方式和CentOS/RHEL比较接近。如果原来的系统本身跑在Linux上,迁移到麒麟服务器版的操作系统层面改动很小;如果原来跑在Windows Server上,那整个部署方式都要重来一遍,工作量会大很多。
这里有一个特别重要的建议:尽量在项目启动早期就锁定目标平台,不要做一套兼容多个架构的方案。混合架构会带来双倍的配置维护成本,而且JVM参数、数据库驱动、中间件License都可能和架构绑定。如果最终目标没有确定,至少要明确一个可运行的最小目标平台,在这个平台上完成全链路验证以后,再考虑扩展。
操作系统选型落地时,我会先执行这几个检查动作:
- 确认系统已安装完整的glibc、zlib、libstdc++等基础库,国产系统的精简安装盘经常缺这些东西,后面跑起来会报各种找不到的错。
- 内核版本不要太低,建议至少4.18以上。某些较老的内核和OpenJDK 11+的容器与epoll机制配合有问题,会导致网络连接异常。
- 检查系统默认locale是否为UTF-8,这个直接影响Java默认字符集行为,后面编码问题很多都来源于此。
- 在一台测试机上把JDK、数据库客户端、Redis、Nginx全部装一遍,跑一个最简单的Spring Boot应用做冒烟测试,确认环境能正常拉起再进入正式改造。
2.2 JDK安装与版本选择的坑
JDK版本是信创改造里特别容易引起团队争议的一个点。我的建议很直接:能上8就上8,团队有余力就上11或17,尽量不要停留在1.6/1.7。原因在于,信创操作系统和国产数据库厂商对Java版本的官方支持列表里,老版本基本都处于放弃维护状态。国产OS自带的软件源里OpenJDK 8是标配,11和17也在逐步跟进,但你指望他们为1.7做适配是不现实的。
从Oracle JDK切换到OpenJDK,最常翻车的点其实是打包在应用里的依赖,而不是Java语言本身。下面这些场景都是我实测遇到过的:
javax.annotation找不到包。JDK 11开始把javax.annotation从默认模块里移除了,老项目如果用了依赖注入的注解,编译时没问题,运行时直接NoClassDefFound。修复方式是引入javax.annotation-api依赖或者改用jakarta版。- JAXB(javax.xml.bind)消失。JDK 11开始JAXB不再是自带模块,凡是项目里使用JAXB做XML解析的,都要额外引入jaxb-api和jaxb-runtime。
- 模块化导致的反射失败。Java 9开始模块系统会对未开放的包做强封装,如果代码里用了
setAccessible访问Java内部类,会抛InaccessibleObjectException。Spring Boot 2.x里面有些反射逻辑会遇到这个问题,一般在启动参数加--add-opens可以规避。 - 编译版本和运行版本不一致。
Unsupported major.minor version 52.0这个经典报错还会出现,哪怕你跑在信创环境上。根本原因还是编译用的JDK高于运行环境的JDK,解决办法就是统一Maven的编译等级和现场部署版本。
JDK发行版的选择上,我建议优先使用操作系统仓库内置维护的OpenJDK版本,好处是安全补丁有人管,后续运维省心。如果你需要指定版本,比如项目团队普遍使用JDK 11,那就自己下载OpenJDK二进制包统一管理。不推荐去使用网上流出的各种“优化版JDK”,兼容性和安全性都没保障。
2.3 环境验证清单
在正式动手之前,我一定会先搭一套最小化验证环境,运行一个环境体检脚本。把这些命令的输出内容整理成表格发给所有相关人确认,能提前暴露大量环境配置问题。
这套脚本的输出立刻就能判断出后续可能踩的坑:locale不是UTF-8,那编码问题基本躲不掉;字体列表为空,PDF导出大概率崩;基础库缺失,中间件可能起不来。这些环境层面的问题,一定要在改造前通过一份环境基线报告确认下来,否则后面排查问题的时候,很多代码侧没问题却在环境侧不断耗时间。
3. 中间件与应用服务器的国产化替换
3.1 什么时候需要换Tomcat
这是团队经常争执的问题。先说结论:如果项目需要过信创目录评审,那应用服务器必须换成国产中间件,比如东方通TongWeb、宝兰德BES、金蝶天燕Apusic。如果只是把底层环境切换到国产操作系统和数据库,使用Tomcat跑在麒麟系统上通常也能通过兼容性验收,但严格按目录要求可能会被扣分。
我的建议是先搞清楚约束条件再行动。如果没被要求替换中间件,Tomcat 9.x跑在OpenJDK 11上是目前兼容性最好、成本最低的组合。如果要求替换,也不要慌,因为你的应用只要是标准WAR包,没有使用Tomcat私有特性,迁移成本并不高。国产中间件基本都遵循Servlet规范,部署、启动、配置逻辑和Tomcat大同小异,只是控制台、目录结构、日志格式上存在差异。
替换中间件的时候要注意,老项目如果用了JNDI数据源、Tomcat的Session持久化、或者依赖Tomcat的类加载顺序,迁移后行为会变。尤其类加载顺序,Tomcat是典型的parent-last模型,某些国产中间件可能相反,这会导致一些框架的版本被容器内置的实现覆盖,出现诡异问题。所以替换中间件一定要留出专门的回归测试时间,不能简单部署完就完事。
3.2 国产中间件的使用要点
我用东方通TongWeb做过几次实际部署,它的管理控制台和Tomcat差别比较明显。部署WAR包可以直接通过管理后台上传,也可以放到应用发布目录重启生效。下面几个点是我总结出来一定会用到的:
- 使用前先核对中间件支持的Servlet版本、JDK版本和你的应用是否匹配。TongWeb 7.0支持Servlet 4.0和JDK 8/11,如果你的应用是基于Servlet 3.1的,那兼容性很好。
- 不要在应用里依赖Tomcat特有的
/webapps、/conf目录结构,部署后路径可能完全不同。 - 日志类库在更换中间件后,可能因为类加载顺序导致日志输出位置变化,建议显式指定SLF4J的绑定实现,避免应用日志和中间件系统日志混在一起。
- JSP页面首次访问速度慢是国产中间件的通病,因为默认是开发模式的动态JSP编译。上线前记得开启预编译,或者在部署后自动编译一遍。
- 数据库连接池尽量在应用侧管理,不要交给中间件,这样以后换中间件不用重配。
宝兰德和金蝶天燕的思路大同小异,本质都是兼容Servlet规范的Java应用服务器。评估选型时可以拿一个典型的WAR包在几款中间件上都部署一遍,看启动速度、控制台易用性、日志规范度,选一款团队最能接受的。
3.3 会话复制与集群配置
原来跑在Tomcat集群上的项目,最常用的方案是Tomcat自带的Session集群复制。换到国产中间件之后,这个行为不一定有对应支持。TongWeb有自己的集群管理,但默认是全节点复制,节点一多会把大量网络带宽耗在Session同步上。我的建议是干脆把会话管理从容器中剥离,使用Spring Session,把Session存到Redis。这样中间件随便换都不影响会话状态,也为以后迁移到云端容器化铺好了路。
改造中一旦把Session外置,有几个点要一并考虑:一是Session序列化的问题,存在Redis里的对象必须实现Serializable,否则反序列化报错;二是Session超时时间要统一配置,不要在应用、容器、Redis三个地方各设一个超时值;三是注意Cookie的域和路径,多应用共享会话时特别容易出问题。
4. 数据库改造:最棘手的一环
4.1 数据库选型与评估
数据库改造是信创项目里工作量最大的环节,尤其是那些跑了很多年的老Oracle系统。信创环境下常见的数据库选型有:达梦DM8、人大金仓KingbaseES、GaussDB、OceanBase、TiDB。达梦对Oracle的兼容性做得比较好,金仓对PostgreSQL和Oracle都有兼容模式,GaussDB适合大规模分布式场景,OceanBase和TiDB都走分布式路线。
选型阶段我最看重的不是市场排名,而是拿实际的SQL去真实库跑一遍。所以我在评估期会做一个SQL方言兼容扫描:把项目里所有SQL文件、MyBatis mapper、JPA实体里的查询、存储过程脚本全部拉出来,用脚本统计用了哪些数据库特性函数。Oracle项目最常见的坑包括:ROWNUM分页、序列NEXTVAL/CURRVAL、CONNECT BY递归查询、NVL函数、SYSDATE时间函数、TO_CHAR/TO_DATE的格式串、空字符串和NULL语义差异。MySQL项目相对简单一些,主要注意表引擎差异、驱动参数、默认排序规则。
选型完成后,还要对目标数据库做一个容量和架构评估。数据量在千万级以内、单机模式能支撑的,就不用选分布式,选单机版的达梦或金仓更稳妥。数据量过亿、并发写入很高、或者有明确的水平扩展需求,才应该考虑分布式方案。分布式数据库的改造复杂度比单机高不少,事务一致性和分页排序的坑非常多,不是万不得已不要为了“先进”给自己找事。
4.2 SQL兼容性与方言适配
SQL兼容性改造是数据库迁移的核心工程。我的标准做法是引入一个数据库方言适配层,让上层业务代码只面向统一的接口,底层根据目标数据库类型自动切换SQL。
具体实操建议:
- MyBatis场景下,配置好Dialect方言。MyBatis Plus的
DbType设置成DM或KINGBASE_ES之后,分页SQL会自动适配。纯MyBatis没有内置方言的,需要自己实现一个拦截器,拦截物理分页SQL并替换为目标数据库的分页语法。 - JPA/Hibernate场景下,设置Hibernate的
hibernate.dialect为对应国产库方言类。Hibernate 6.x对国产库的支持已经比较完善,但老项目如果停留在Hibernate 3.x,改造的难度极大,可能要考虑ORM框架升级。 - 存储过程尽量反哺为Java代码。数据库厂商的迁移工具可以把Oracle的PL/SQL转成达梦的SQL,但转换后的性能和维护性很难保证。这是个技术债清算的好时机,把存储过程里的业务逻辑用Java Service实现,以后扩展、测试、维护都轻松。
- 统一时间处理。代码里的
SYSDATE、NOW()尽量改成Java侧传入参数,用LocalDateTime统一管理,既避免方言差异,也方便单元测试。 - 分页逻辑统一走框架。不要在业务代码里手写
ROWNUM或者LIMIT,那个地方的方言耦合是最严重的。
一个真实的例子可以说明问题:有个报表模块用了一条Oracle递归查询SQL,里面用了START WITH...CONNECT BY。迁到金仓后,逻辑层面其实兼容,但需要开启Oracle兼容模式,开启后大部分PL/SQL都能过,可查询性能差了十倍。最终我把它改成Java循环+批量查询,解析父子关系放到内存里做,速度从20秒降到了2秒。数据库兼容模式是兜底方案,不该成为长期依赖,真正高效的做法是把复杂逻辑下沉到合理的层。
4.3 数据迁移实战
数据迁移绝对不是一个复制粘贴的过程,我总结了一套标准的操作步骤:
- 先确定迁移的业务范围和停机窗口。信创改造往往伴随新旧系统并行和切换,设计好回滚方案比什么都重要。
- 导出源库完整的结构信息,包括表、索引、约束、视图、触发器、序列、存储过程。
- 做DDL转换。达梦自带的Oracle迁移工具、金仓的Migration Toolkit都能做,但对复杂的DDL支持不会100%到位,必须人工review每一张表、每一个索引的定义。
- 做全量数据抽取,这部分推荐用程序迁移,灵活度更高。数据量不太大的情况下,写个Java迁移程序,挨张表一边查询一边插入,并且记录迁移日志,方便失败重跑。
- 增量数据同步。全量迁移结束后,在业务停机窗口前往往还有数据产生,需要做增量同步。常见方案是源库加时间戳字段,增量轮询并同步,切换前再做最后一小段增量刷新。
- 数据校验。迁移完成后不是直接交割,要做源库和目标库的比对:行数一致、关键字段值一致、空值分布一致,最好写一个自动比对脚本,用MD5聚合的方式校验每张表的关键字段哈希值。
- 切换与回滚。正式切换后保留源库一段时间的只读访问,一旦发现异常可以快速回滚。
这里最容易忽略的坑是LOB字段。我做过一个惨痛案例:一张合同附件表,BLOB字段在迁移工具的默认配置下被转成了VARCHAR(4000),一半数据因为长度超限制被截断,应用读取时报“流已关闭”。这类问题只能靠迁移后的抽样对比来发现,所以校验环节绝对不能省。
4.4 连接池与事务配置
Java应用连接国产数据库时,连接池配置也需要针对性调整。HikariCP是首选,它足够轻量,对JDBC的支持也好。需要注意的配置项有:
- 确认数据库JDBC驱动小版本和数据库小版本匹配。达梦DM8的驱动版本不匹配,启动时可能报“不支持的协议版本”,很让人头大。
- 连接超时建议调大。国产数据库在一些硬件条件一般的机器上,首次连接建立比较慢,默认的10秒超时可能不够,我实际推荐配成30秒。
- 事务隔离级别不要依赖默认值。国产库的默认隔离级别与Oracle/MySQL并不一样,如果业务对隔离级别有要求,最稳妥是在连接池配置里显式设置
transaction-isolation。 - SQL执行慢了不要急着加索引。先用
EXPLAIN看执行计划,国产库的优化器行为跟Oracle不同。我处理过很多慢查询,最终有效的优化方式都是把NOT IN改成NOT EXISTS、把大子查询改成JOIN。
连接池参数可以参考这个初始值:初始连接5,最小空闲5,最大连接50,连接超时30秒,空闲超时10分钟,校验查询用SELECT 1。这套参数实测下来比较稳定,后续根据压测结果微调即可。
5. 代码层面的适配细节
5.1 JDBC驱动与类加载
数据库驱动更换之后,代码层面最简单也最折磨人的问题是类加载和依赖冲突。我在一个Spring Boot项目里遇到过一个很经典的故障:把Oracle驱动换成达梦驱动后,应用启动时提示找不到合适的驱动。用mvn dependency:tree一查,发现项目里还残留着ojdbc8.jar,两个JDBC驱动同时存在于Classpath,服务加载机制导致注册顺序混乱。解决方案就是把依赖树里残存的其他数据库驱动全部排除掉,只保留目标数据库的驱动。
我把驱动适配的要点整理一下:
- Oracle的驱动类是
oracle.jdbc.OracleDriver,达梦是dm.jdbc.driver.DmDriver,金仓是com.kingbase8.Driver。不要用反射字符串去拼驱动类名,写在配置里最稳。 - JDBC URL差异要注意:达梦常见格式是
jdbc:dm://ip:5236/schema,里面可以带compatibleMode=Oracle等参数;金仓格式是jdbc:kingbase8://ip:54321/db,driverType=1表示走本地socket。这些参数会改变底层行为,务必测试。 - 数据源配置如果之前写在应用里,换库后只要改配置就行;如果用了中间件的JNDI数据源,要把这种维护职责留在中间件侧,代码里保持
lookup逻辑不变。 - 如果是Spring + MyBatis组合,注意MyBatis配置里
jdbcTypeForNull等参数在国产库上的行为可能不同。默认值在Oracle和国产库上表现就不一样,需要统一设置为NULL,避免插入时语句报错。
5.2 文件系统与编码问题
文件系统和编码问题是我在信创改造中掉头发最多的模块,不展开讲清楚真的对不起看这篇文章的人。
路径问题。很多老代码里写死了Windows风格的D:/upload或者C:\\\\temp路径,部署到麒麟系统后直接找不到目录。改造时要统一把文件存储路径外置到配置项,在部署时由运维指定,代码里一律使用相对路径或通过Spring的ResourceLoader加载。
编码问题分三层:
- JVM默认字符集。现在几乎所有的国产OS默认locale都不是UTF-8,如果你不在JVM启动参数里设置
-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8,应用读文件和写文件时的默认编码就可能不是UTF-8,中文乱码立刻出现。 - 外部文件读取。代码里的
FileReader、FileWriter默认使用系统编码,改成指定UTF-8的InputStreamReader/OutputStreamWriter是必须做的一次大扫除。 - 压缩和解压。
ZipOutputStream默认的编码是系统字符集,打出的压缩包里有中文文件名时,到别的机器解压会出现乱码。需要在代码里显式设置ZipOutputStream的encoding为UTF-8。
我的做法是,在代码改造启动前用静态扫描工具搜一遍项目里的硬编码路径、FileReader、ZipOutputStream这些高风险API,列成清单挨个修,改完再跑全量回归。这种事靠人肉翻代码,效率太低,而且一定会漏。
5.3 加密、证书与国密算法
信创语境下,安全这块通常不止要求能跑,还明确要求使用国密算法。SM2(非对称)、SM3(哈希)、SM4(对称)是国产密码标准。从商用算法切换到国密算法时,核心原则是集中封装、分散调用。
我推荐的落地路径:
- 引入Bouncy Castle或者使用厂商提供的国密SDK,业务代码只面向统一的加密服务接口。
- 把AES替换为SM4时,算法的更改集中在加密组件内部。这里要注意,SM4的分组大小与AES一致,但密钥长度和初始向量IV的使用方式可能有差异,改造时不能只改算法名。
- RSA替换为SM2时,签名验签的编码格式要特别小心。SM2签名结果通常以DER编码格式输出,但项目实际传输时可能是原始R值+S值拼接的格式,两种协议改起来完全不同。
- HTTPS证书层面,服务端更换为国密证书需要考虑中间件的支持度。Tomcat对国密SSL支持不友好,而东方通这类国产中间件通常原生支持,这也是替换中间件的一个重要理由。
我的切身体会是,加密算法这类改动波及面很大,一旦在业务代码里散落着Cipher.getInstance("RSA")这样的调用,改造时就要做一次全量的加密算法调用点审计。所以如果你的老项目平时代码规范一般,这一步宁可多花时间做静态扫描,也不要放过任何一个加密入口。
5.4 前端与浏览器兼容
信创改造不能只盯着后端。很多政务项目的前端环境会换成特殊的客户端浏览器,这些浏览器大多是Chromium内核,对现代Web标准支持还可以。但老系统如果还依赖IE专用写法——ActiveX控件、VBScript、或者各种私有的浏览器插件,那这部分功能基本要重写。
我遇到过的前端适配典型问题:
- JSP页面上嵌入的Applet控件,这个在信创环境直接失效,功能必须用HTML5或WebSocket方案重写。
- 前端字体依赖本地系统字体,切到信创操作系统后字体缺失,页面排版错乱。这类问题需要补充合适的中文字体文件,或者引入Web Font方案。
- 打印控件不兼容。很多老系统用Lodop或专用打印插件,信创终端上需要对应信创版本的打印服务,这块要提前向厂商确认。
- 文件上传下载插件如果之前用了Flash,现阶段几乎全部不可用,需要替换为原生的HTML5上传。
前端的改造计划一定不要压缩测试时间,因为浏览器兼容性问题只有在真实信创终端上才能暴露,模拟器经常蒙混过关。
6. 常见问题与排查技巧实录
6.1 启动即报错的经典案例
信创改造中遇到最多的报错,其实很多都是环境配置类问题,代码逻辑反而相对干净。我把几个高频率且极具代表性的排错了列成一个速查表,方便你遇到同类问题时快速定位。
| 报错信息 | 根因 | 排查思路与解决办法 |
|---|---|---|
Unsupported major.minor version 52.0 |
运行JDK版本低于编译JDK版本 | 统一下发JDK 8或JDK 11,用Maven指定编译版本 |
ClassNotFoundException: oracle.jdbc.driver.OracleDriver |
依赖树里残留老驱动 | 用mvn dependency:tree排除掉所有非目标库的驱动 |
No suitable driver |
JDBC URL格式不对或驱动未加载 | 检查driver-class-name和url格式是否匹配目标库 |
UnsatisfiedLinkError: no xxx in java.library.path |
JNI本地库缺失或架构不匹配 | 确认是否有目标平台二进制,没有则用Java替代实现 |
InaccessibleObjectException |
JDK模块化限制Accessible操作 | 启动参数加--add-opens,或修复反射逻辑 |
There is insufficient memory for the Java Runtime Environment |
物理内存不足或swap太小 | 调整-Xmx,扩容swap,检查ActiveProcessorCount |
举一个真实排障过程:一台新到的ARM服务器部署Spring Boot服务时,持续报内存不足错误。free -g看内存明明还有十几G,但JVM就是起不来。最后定位是服务器可用内存碎片和OS参数限制,把-XX:ActiveProcessorCount=4加进去后,GC线程数降到正常值,服务稳定启动。这类问题在信创新服务器上特别多,因为服务器厂商默认系统配置和通用Linux发行版差异很大。
6.2 运行期诡异的性能问题
改造完成后,最常遇到的问题不是崩溃,而是比原来慢几倍。我排查过大量这类情况,绝大多数根因就以下几类:
- SQL走了全表扫描。尤其从Oracle迁移到国产库后,原有些索引没有被正确转换,或者SQL写法在不同优化器下表现完全不同。这种问题一定要看执行计划,达梦用
EXPLAIN,金仓用EXPLAIN ANALYZE,对比优化器选的路和原Oracle的差异,再决定加索引还是改SQL。 - 连接池耗尽。如果实际排查发现大量线程阻塞在获取数据库连接上,基本是连接池配置偏小或驱动版本存在连接泄漏。升级驱动版本,打开HikariCP的日志监控,调大最大连接数观察一段时间。
- JSP编译拖慢首屏。国产中间件默认不预编译JSP,第一个用户访问时触发编译,页面白屏好几秒。解决方案是部署完成后手工触发预编译,或者开启中间件的预编译参数。
- 全文检索功能性能下降。Oracle Text迁移到国产库后,分词器和评分逻辑不同,检索耗时明显增加。如果是全库扫描型功能,考虑引入ElasticSearch这类专门检索引擎,不要在数据库层面硬扛。
排查性能问题时,一定要先做基准对比。不要直接怀疑代码,先在同一个应用、同一个数据量下对比新旧环境的指标,确定是环境性能问题还是代码问题,再往下拆。
6.3 信创环境测试注意事项
信创改造的验收通常要做兼容性测试,这个环节如果前期准备不足,很容易翻车。我在项目里通常会提前做三件事:
- 搭建一个独立的信创测试环境,与开发环境隔离。环境参数尽量与生产对齐,包括CPU架构、操作系统版本、JDK版本、数据库版本。不要用Docker出来骗自己,因为很多问题只有在真实物理环境或者完整虚拟化环境下才会暴露。
- 测试用例覆盖高频业务路径,包括基础增删改查、列表分页、权限控制、报表导出、附件上传下载、定时任务、单点登录、打印功能。这些是业务系统的通用主干,保证它们没问题以后,再铺开细节功能测试。
- 压测数据量要和当前生产量相当,甚至略高。很多团队用几百条数据验证分页性能,结果一到生产几千万数据量直接卡死。至少用生产数据量的50%来做基准压测,才能对容量和性能有底。
如果项目有外部系统对接,还要把对接场景纳入测试,因为接口协议、报文编码、HTTPS证书可能都因为环境变化而修改过。这块经常被遗忘,却是上线之后最容易被调用方投诉的部分。
结尾
坦白讲,信创改造做了几个项目之后,我最大的体会是:这个事真正考验的不是单点技术有多深,而是你能不能把一个复杂系统拆成环境、中间件、数据库、代码四个层面,挨个把差异梳理清楚,验证到位。Java本身的跨平台能力确实让改造少了很多血泪,但那些隐藏在JNI本地库、字体渲染、SQL方言、JDK内部API里的坑,一个都不会少。每次踩完坑我都会把排障过程记录下来,再碰到类似问题就能直接对照排查,省下大把时间。如果你正在进入这个改造周期,建议先把环境摸底做扎实,再谈代码迁移,顺序真的很重要。