升級JDK8的坎坷之路

zy苦行僧發表於2021-11-08

為更好的適應JAVA技術的發展,使用更先進及前沿的技術。所以推出將我們現在使用的JDK1.6(1.7)及tomcat6(7)升級至JDK1.8及tomcat8,使我們的系統獲得更好的效能,更好適應未來及節約成本


一、升級JDK8流程

1、伺服器JDK版本升級
將JDK1.8版本安裝到伺服器上

2、老系統升級時專用流程
將老程式碼(1.6或1.7編譯的)部署到升級的伺服器上(JDK有向下相容原則),灰度觀察一段時間(但也有部分不相容的內容)檢視程式碼執行是否有問題

JDK不向下相容部分:
https://www.oracle.com/java/technologies/compatibility.html

3、升級專案程式碼中的JDK
3.1、在專案主pom.xml檔案中新增編譯配置,如果存在“maven-compiler-plugin”則修改為如下配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.5.1</version>
    <configuration>
        <encoding>UTF-8</encoding>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

3.2、若是我們的api的jar包被其他系統使用,則設定對外api包的pom.xml編譯環境為原JDK版本

前提是其他系統使用的是比1.8低的版本。
如果其他系統版本低,是無法使用我們高版本編譯的api的


3.3、其他modle裡面如果也存在的話,則刪除maven-compiler-plugin外掛

3.4、修改專案JDK版本為1.8,在專案上”右鍵”選擇“open module settings”,然後選擇SDKs的“+”設定好JDK為1.8,並使用

3.5、選擇左上角的File -》 settings開啟對話方塊,在搜尋框裡面輸入“java Compiler”選擇,確保Target bytercode version 為1.8,並且API欄為原JDK版本

4、部署新程式碼
部署新程式碼(1.8編譯的)部署到伺服器上,灰度觀察一段時間,檢視程式碼執行是否有問題


二、升級過程中可能遇到的問題

一、JVM在JDK8的新特性
去除了永久代(PermGen),新增元空間(Metaspace);

永久代的引數-XX:PermSize和-XX:MaxPermSize也被移除了。如果在啟用時設定了這兩個引數,會被忽略並給出警告。在升級JDK8時如果使用了這兩個引數需要注意,將其刪除。

建議設定MetaspaceSize和MaxMetaspaceSize這2個引數,否則可能出現本地記憶體被佔用完,導致程式被直接殺死
-XX:MetaspaceSize
-XX:MaxMetaspaceSize

可以通過以下連結對永久代的去除及元空間的新增進行初步的瞭解。
參考:
https://blog.csdn.net/zhushuai1221/article/details/52122880
https://blog.csdn.net/sczyh22/article/details/46662279
https://www.jianshu.com/p/69ccaab0add7

二、jar包有誤(衝突或版本過低)
1、Invalid byte tag in constant pool: 18

原因:aspectjweaver包1.6版本太低,升級至1.8

<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
 <version>1.8.9</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.9</version>
</dependency>

2、java.io.IOException: invalid constant type: 18

原因:javassist包版本太低,jdk1.8只支援3.18及以上版本

三、JDK8與spring3.x不相容,升級spring4.x
在使用JDK8 + spring3.1時,啟動專案會報以下錯誤

java.beans.IntrospectionException: 
type mismatch between read and write method。

原因:
Java 8強制類中的getter和setter必須具有相同的型別,專案中引用的許可權依賴中的類AccessPath中的set,get方法型別不相同導致的

解決辦法:
升級spring版本,目前專案升級到了4.x版本(例:4.1.6.RELEASE、4.3.18.RELEASE)

參考:
https://my.oschina.net/smzd/blog/611731
https://github.com/spring-projects/spring-framework/issues/17053

四、spring3.x升級Spring4.x時,web系統引數轉換問題
問題:
升級Spring4.x後,引數轉換不相容spring4,如下圖:

解決方案:
1、使用spring原生的org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
2、刪除配置 <property name="failOnUnknownProperties" value="false"/>
出參轉JSON,用不到這個功能
3、Spring3使用的Jackson1.X;Spring4使用的是Jackson2.X;
因此升級4後,由於配置中原本宣告objectMapper為1.X,自動注入MappingJackson2JsonView的也是1.X,造成導致轉換異常,需要手動設定objectMapper的物件引用

<--Jackson1.X-->
<bean id="objectMapper" class="org.codehaus.jackson.map.ObjectMapper">
<property name="dateFormat" ref="dateFormat"></property>
<property name="serializationInclusion">
<util:constant
static-field="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_NULL" />
</property>
</bean>
​
<--Jackson2.X-->
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat" ref="dateFormat">
</property>
<property name="serializationInclusion">
<util:constant static-field="com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL"/>
</property>
</bean>

五、JDK8與Tomcat8的升級
升級到tomcat8遇到的問題,tomcat 啟動起來了,但是應用不能正常訪問,看日誌如下報錯

七月 19, 2019 10:21:49 上午 org.apache.catalina.core.StandardContext startInternal
      嚴重: One or more listeners failed to start. Full details will be found in the appropriate container log file
七月 19, 2019 10:21:49 上午 org.apache.catalina.core.StandardContext startInternal
       嚴重: Context [] startup failed due to previous errors

提示更多的詳細資訊在容器日誌裡,然而容器沒有其他日誌,需要增加容器預設日誌配置,
查詢tomcat8官網,得到如下資訊,tomcat預設使用JULI作為日誌輸入,JULI是Apache Commons Logging的一個分支

按照官網提示增加如下配置,找到對應的日誌檔案

檢視具體的異常資訊,進一步解決問題:
後端接收不到前端提交的表單請求引數時,需要檢查下Tomcat的maxPostSize配置:從apache-tomcat-7.0.63 開始,引數 maxPostSize 的含義就變了: 如果將值設定為 0,表示 POST 最大值為 0,不限制 POST 大小需要將值設定為 -1。在此版本之前設定為 0 表示不限制 POST 大小。

tomcat8 日誌官網:
https://tomcat.apache.org/tomcat-8.5-doc/logging.html

六、spring5.X與velocity不相容
Spring5.x不再支援velocity,如果前端已經使用velocity的話,請使用spring4.x

七、JDK6和JDK8型別推斷與過載解析的差異
問題:
過載方法遇到返回結果型別為泛型時,對過載方法的選擇上 JDK6和JDK8會有區別。有可能會出現呼叫錯誤的過載方法導致異常。

案例:
Spring的集合判空方法:org.springframework.util.CollectionUtils.isEmpty

在這裡插入圖片描述
JDK6正常,JDK8卻會包轉換異常

原因:
JDK8 中的型別推斷與過載解析與JDK6有很大區別,JDK8呼叫isEmpty過載方法時選擇過載方法錯誤報錯。

差異解析:
https://blog.csdn.net/on_1y/article/details/50650014

解決:
方法一:手動設定引用型別接收泛型結果,再把型別傳到過載方法中
方法二:不使用第三方工具,重寫實現方法

八、JDK6和JDK8在配置中的listener問題
【若沒有申請新機器,而是基於老版本直接升級。可能出現的問題】

問題描述:
切換tomcat8的時候,會提示找不到兩個listener

java.lang.ClassNotFoundException: org.apache.catalina.core.JasperListener
java.lang.ClassNotFoundException: org.apache.catalina.mbeans.ServerLifecycleListener

問題原因:
(1) tomcat啟動命令為

/export/servers/tomcat8.0.30/bin/startup.sh -config /export/Instances/o2o.afs.web/server1/conf/server.xml

(2)配置檔案為原先tomcat6的配置檔案,而tomcat8沒有這兩個listener
解決方式:
修改配置檔案:手動修改 或 通過指令碼修改

sed -i '/org.apache.catalina.core.JasperListener/d' /export/Instances/*/server1/conf/server.xml
sed -i '/org.apache.catalina.mbeans.ServerLifecycleListener/d' /export/Instances/*/server1/conf/server.xml
​
指令碼含義:
sed -i(-i 修改檔案) 
'/org.apache.catalina.core.JasperListener(找到對應語句所在的行)
/d(d為刪除)
' /export/Instances/*/server1/conf/server.xml (對該檔案進行操作)

九、推薦JDK8版本
早期JDK1.8版本對lambda支援較差,存在jvm crash風險
請升級到JDK1.8.0_45及以上版本


------The End------

感謝大家看到最後,文章持續更新!歡迎大家指出我的文章的不足之處,也歡迎大家關注、收藏+分享

如果這個辦法對您有用,或者您希望持續關注,也可以掃描下方二維碼或者在微信公眾號中搜尋【碼路無涯】


相關文章