最近这一个月成为我这几年来最忙最累最绝望的日子,身为一个不太熟悉Java的人需要完成以下的应用软件升级工作:
1. Java 从 8 到 Java 17
2. Spring 从 3 到 5
3. Hibernate 从 3 到 5
4. Genesys Voice Platform Call Flow 从 8.1.2 到 8.1.5
5. 其他用到的模块比如log4j, common-cli, sqljdbc, 等等
6. IBM MQ Client 7 到 9
人就是这样,越不熟悉的,就越不想做,前两年做了一次技术更新,就想着以后再也不要做了。所以这次任务来了,第一反应是推掉,之前有个修改请求就成功地推给外包了。这次技术更新任务估算推给了外包,想着万一要真正做也是可以找他来做。可是到了任务真正下来的时候,跟老板一商量,不打算给外包,手头上也没有Java程序员,真是怕什么来什么,还得自己这个菜鸟上,于是乎艰难而绝望的日子就开始了。
任务当然从升级Java开始,一上了Java17,jaxb和jaxws就出现了编译错误。虽然不知道这两个是啥玩意,就按照名字下载,加入了编译没问题了。
想着hibernate和Spring是大头,先升级其他的,下载了其他模块的更新版本,一切都还算顺利,想着到hibernate和Spring的时候不也这样嘛,下载新的类库,一编译成功,那不就得了。
到了hibernate和Spring的时候,情况完全不是这么回事,各种编译错误,看不懂就按照名字找类库加上,排除了所有的编译错误之后,上JBoss遇到大问题了,总说不行,就是上下文载入不了,死活载入不了,不知道啥原因,这样试,那样试,啥办法都想了,啥库都往里面加,跟个无头苍蝇似的,还是不行啊,就是不行啊。
在网上找了找,人家也说升级的时候最好一步一步来,从3到4再到5。既然自己的猜想的方法不管用,就应该用最基本的方法来。首先把一切还原到最初的Spring3和hibernate3,JBoss里面跑起来没问题。考虑到Spring应该是主导,并且向下兼容,就先升级到4,升级的方法也改变了,不能按照原有版本的文件名找相应的升级文件,应该下载全套的,比如Spring4全套有哪些文件,先全部下载全部加上,没问题。所以就采用了下面的升级路径:
Spring4和Hibernate3 - 没问题
Spring4和Hibernate4 - 没问题
Spring4和Hibernate5 - 没问题
Spring5和Hibernate5 - 没问题
这两个组件都采用全套的文件,所以打包完了之后只是有个别的一些数据库的操作做一点小的改动,编译成功,并且也能运行在JBoss里面,当时信心大增,很受鼓舞,以为最难的事情搞定了。
那天突然想起来,我们还有在Tomcat上面用Java写的Call Flow也需要升级啊,这就傻眼了,我哪会Call Flow啊,导入相应的项目文件,根本不能打包,不识别,需要加载GVP本身的外接件,也试了好半天,怎么也加不进去,后来摸索到了Eclipse加入外接件的方法,成功地安装上了,Call Flow能看见了,但是不能打包啊,源文件版本太低,需要升级。我尝试升级了,根本不行,Genesys的人跟我说不能直接升级必须按照下面的方法来升级:
8.1.2 到 8.1.3 - 这个版本只有Windows 8上面做
8.1.3 到 8.1.4
8.1.4 到 8.1.5
最后完成了升级,看到log4j 成功地被转换到log4j2我还是挺开心的,毕竟自己手动做会有很多麻烦。
上面的升级过程,只有JBoss是有真正跑了Runtime的测试,其他的只在打包阶段而已。到了真正的目标环境上面问题就很大了,Call Flow倒还好,两个打入的,一个打出的,都还调试得顺顺利利的,acknowledge和电话录音都好着呢,电话通知的也可以激活。
JBoss的Runtime测试是做过了,我忘记还有命令行的一个程序,这个一跑起来完全不是这么回事,到了Java17完全跑不了,各种错误,显示一些自己都不认识的类名,程序里面也没看到用的,就是没有。那天我使用各种方法,就是不行,周四晚上做到12点,灰溜溜地回家了,跟项目经理说,明天你等我的消息,搞得定我就让你来测试,不能你就别来。
一开始跑的时候出各种类库找不到的问题,手动加入了下面两个类库:
- jboss-logging-3.3.0.Final.jar
- jta-1.1.jar
好像还有jaxb-api和jaxb-impl之类的,加上了以后才没有出现类库不存在的错误。
这些个库在JBoss里面都不需要加载的,就是上下文初始化在JBoss和命令行是不一样的。
周五我找了一个做Java的朋友来帮我,人家也很给力,跟我进行了三次Zoom,主要的错误就是下面这个:
module java.base does not "opens java.lang" to unnamed module @746c215d
导致Error creating bean with name 'sessionFactory' defined in class path resource
网上说了,要加下面这个参数在JVM初始化的时候:
--add-opens java.base/java.lang=ALL-UNNAMED
我在Eclipse里面也加了,还是不行。后来我灵光一闪,想着Java8能不能跑,结果一切换发现可以。当时内心就有了想说服用户不进行Java版本的升级工作的想法了。因为Java8的延长支持期甚至比Java17的延长支持期更长,只是主要的支持的时间比17少两年。
关键我初始化Spring的跟Hibernate有关的Bean都是用xml的方式,我和我朋友都非常担心是因为用的方法过于传统,导致新版本不支持,可问题是我们都不知道该怎样该配置文件。我们用的是Spring orm, 我朋友用的是Spring Bot。
可问题是JBoss上面跑一点问题没有,那是怎么回事。我顺便也问我朋友jaxb是干嘛的,她说就是从xml到bean的转换。既然是Bean初始化的问题,那必定就是跟Jaxb有关,我朋友建议我使用更新一点的版本,我就找了jaxb-api和jaxb-impl更新的版本来试,还是不行。后来发现是新版旧版都有才能行,就是下面这四个文件:
- jaxb-api-2.4.0-b180830.0359.jar
- jaxb-core-4.0.0-M4.jar
- jaxb-impl-2.4.0-b180830.0438.jar
- jaxb-impl-4.0.0-M4.jar
正当我很开心地准备收工的时候,突然发现我的Hibernate的数据库操作根本是无效的,没有报错,但是数据没有插入。
一开始的时候是出现这个错误:
Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
于是我就在写数据的代码之前加了一行,以上错误就消失了:
getHibernateTemplate().setCheckWriteOperations(false);
getHibernateTemplate().saveOrUpdate(logEntry);
没有错误不代表没问题,我发现数据根本没有插入。于是开始在网上疯狂地找,尝试各种方法,昨天晚上做到很晚,还是没结果,后来我强迫自己4点必须睡觉,但是各种不甘心。
今天早上一起来就开始继续调试,突然JBoss跟我投诉了下面的问题,我的包无法部署:
Could not initialize class org.apache.logging.log4j.core.LoggerContext
这个问题在于log4j-api和log4j-core的不兼容性:
JBoss log4j-api 版本:log4j-api-2.14.0.redhat-00002
应用程序log4j-api版本:log4j-api-2.17.2
解决这个问题的方法是替换JBoss log4j-api的版本:
1. 把log4j-api-2.17.2.jar 拷贝到如下JBoss的路径\modules\system\layers\base\org\apache\logging\log4j\api\main
2. 修改该路径的module.xml文件中版本的内容
那个数据库的问题是这样解决的:
就是要加入下面的Spring类库:
spring-aop-5.3.18.jar
并且在Hibernate配置文件做以下修改:
文件开头要用新的名字空间:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
后面要加上
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
另外数据操作代码的方法前面要加:
@Transactional
下周二上班,希望真正的集成测试一切顺利吧。