最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JDK8升級(jí)JDK17過(guò)程中踩到的一些坑

 更新時(shí)間:2023年07月04日 16:11:42   作者:movee  
這篇文章主要給大家介紹了關(guān)于JDK8升級(jí)JDK17過(guò)程中踩到的一些坑,對(duì)于一些老的項(xiàng)目,升級(jí)到JDK8則存在一些兼容性問(wèn)題,是否升級(jí)需要酌情考慮,需要的朋友可以參考下

1 前言

JDK8雖然非常好,但是JDK版本已經(jīng)發(fā)布到JDK20了,且JDK8后的版本升級(jí)了很多新的特性,如模塊化、ZGC以及虛擬線(xiàn)程、結(jié)構(gòu)性并發(fā)等,也是非常有吸引力的,所以決定將基于JDK8的項(xiàng)目升級(jí)到最近的LTS版本JDK17。

2 升級(jí)過(guò)程記錄

2.1 安裝JDK17

下載JDK17的最新版本jdk-17_linux-x64_bin.tar.gz,解壓縮后移動(dòng)到/usr/lib/jvm/目錄下

$ sudo su -
# tar -xzf jdk-17_linux-x64_bin.tar.gz
# mv jdk-17.0.2 /usr/lib/jvm/java-17

然后修改~/.bashrc,設(shè)置java相關(guān)環(huán)境變量為JDK17

# vim ~/.bashrc

export JAVA_HOME=/usr/lib/jvm/java-17
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

環(huán)境變量生效后,檢查當(dāng)前的jdk版本為JDK17

# source ~/.bashrc

# java -version
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)

2.2 升級(jí)spring版本并編譯

修改項(xiàng)目的pom.xml文件,將spring boot和spring cloud版本由

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
    </properties>

修改為最新正式發(fā)布版本:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <spring-cloud.version>2022.0.2</spring-cloud.version>
    </properties>

編譯項(xiàng)目,報(bào)以下錯(cuò)誤:

程序包javax.servlet.http不存在
程序包javax.validation不存在

原因是原先javax包的名字改為jakarta了,將項(xiàng)目中所有依賴(lài)javax包的地方替換為jakarta

繼續(xù)編譯,報(bào)以下錯(cuò)誤:

[ERROR] 找不到符號(hào)
[ERROR]   符號(hào):   類(lèi) EnableEurekaClient
[ERROR]   位置: 程序包 org.springframework.cloud.netflix.eureka

原因是新版本沒(méi)有@EnableEurekaClient注解了,替換為@EnableDiscoveryClient

繼續(xù)編譯,報(bào)以下錯(cuò)誤:

[ERROR]  找不到符號(hào)
[ERROR]   符號(hào):   方法 apply()
[ERROR]   位置: 接口 io.github.resilience4j.core.functions.CheckedSupplier<java.lang.Object>

原因是resilience4jCheckedSupplier接口新版本沒(méi)有apply()方法了,改為get()方法

繼續(xù)編譯,報(bào)以下錯(cuò)誤:

[ERROR]  對(duì)于RetryableException(int,java.lang.String,feign.Request.HttpMethod,java.util.Date), 找不到合適的構(gòu)造器
[ERROR]     構(gòu)造器 feign.RetryableException.RetryableException(int,java.lang.String,feign.Request.HttpMethod,java.lang.Throwable,java.util.Date,feign.Request)不適用
[ERROR]       (實(shí)際參數(shù)列表和形式參數(shù)列表長(zhǎng)度不同)
[ERROR]     構(gòu)造器 feign.RetryableException.RetryableException(int,java.lang.String,feign.Request.HttpMethod,java.util.Date,feign.Request)不適用
[ERROR]       (實(shí)際參數(shù)列表和形式參數(shù)列表長(zhǎng)度不同)

原因是openfeign新版本的RetryableException異常類(lèi)的構(gòu)造函數(shù)發(fā)生了變化,根據(jù)需要將舊代碼:

    @Bean
    public ErrorDecoder feignError() {
        return (key, response) -> {
            if (response.status() >= 500) {
                FeignException exception = FeignException.errorStatus(key, response);
                return new RetryableException(
                        response.status(),
                        exception.getMessage(),
                        response.request().httpMethod(),
                        new Date());
            }
            // 其他異常交給Default去解碼處理
            return defaultErrorDecoder.decode(key, response);
        };
    }

改為以下代碼

    @Bean
    public ErrorDecoder feignError() {
        return (key, response) -> {
            if (response.status() >= 500) {
                FeignException exception = FeignException.errorStatus(key, response);
                return new RetryableException(
                        response.status(),
                        exception.getMessage(),
                        response.request().httpMethod(),
                        new Date(),
                        response.request());
            }
            // 其他異常交給Default去解碼處理
            return defaultErrorDecoder.decode(key, response);
        };
    }

改為后繼續(xù)編譯,報(bào)以下錯(cuò)誤:

程序包org.junit不存在
程序包org.junit.runner不存在
程序包junit.framework不存在

這是因?yàn)榕f版本使用的是junit4,改為junit5相應(yīng)的注解。即將:

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@Ignore
@RunWith(MockitoJUnitRunner.class)
public class FileSyncerTest {
    @Before
    public void setUp() {
    }
    @Test
    public void testCase1() throws Exception {
    }
}

改為

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
@Disabled
@ExtendWith(MockitoExtension.class)
public class FileSyncerTest {
    @BeforeEach
    public void setUp() {
    }
    @Test
    public void testCase1() throws Exception {
    }
}

改為后繼續(xù)編譯,編譯通過(guò)。

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.582 s (Wall Clock)
[INFO] Finished at: 2023-05-04T16:39:42+08:00
[INFO] Final Memory: 59M/214M
[INFO] ------------------------------------------------------------------------

2.3 啟動(dòng)項(xiàng)目

編譯通過(guò)后啟動(dòng)項(xiàng)目,啟動(dòng)失敗,報(bào)以下錯(cuò)誤:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @7634b327
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
    at net.sf.cglib.core.ReflectUtils$2.run(ReflectUtils.java:56)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:318)
    at net.sf.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:46)

這是因?yàn)閺腏DK9開(kāi)始支持模塊化了,項(xiàng)目中使用的部分組件可能還沒(méi)有支持模塊化,所以需要在jar包啟動(dòng)時(shí)添加add-opens jvm啟動(dòng)參數(shù)參數(shù),我是通過(guò)在pom文件中添加build參數(shù)實(shí)現(xiàn)的:

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!-- 添加 add-opens jvm參數(shù) -->
                    <jvmArguments>
                        --add-opens=java.base/java.lang=ALL-UNNAMED
                        --add-opens=java.base/java.util=ALL-UNNAMED
                        --add-exports=java.base/sun.security.ssl=ALL-UNNAMED
                        --add-opens=java.base/sun.security.ssl.internal.ssl=ALL-UNNAMED
                    </jvmArguments>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

修改完后重新編譯啟動(dòng),啟動(dòng)仍然失敗,報(bào)一下錯(cuò)誤:

Caused by: java.lang.IllegalArgumentException: @RequestMapping annotation not allowed on @FeignClient interfaces

根據(jù)錯(cuò)誤提示,@RequestMapping注解不能添加在@FeignClient接口上了,改為通過(guò)在@FeignClient注解的path屬性攜帶,即由:

@FeignClient(url = "127.0.0.1:8080", name = "service-feign")
@RequestMapping("/service")
public interface ServiceFeign {
}

改為:

@FeignClient(url = "127.0.0.1:8080", name = "service-feign", path = "/service")
public interface ServiceFeign {
}

修改完后重新編譯啟動(dòng),啟動(dòng)仍然失敗,報(bào)以下錯(cuò)誤:

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
Caused by: java.lang.NullPointerException: null

這是因?yàn)轫?xiàng)目中使用了knife4j,由于版本比較低,底層依賴(lài)的是spring-fox,支持的是openapi 2.x版本,而spring boot 3.0只支持openapi 3.x版本,所以knife4j版本依賴(lài)由:

    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
        <version>2.0.5</version>
    </dependency>

改為:

    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
        <version>4.1.0</version>
    </dependency>

同時(shí)將swagger的相關(guān)注解@Api、@ApiOperation、@ApiParam、@ApiModel 、@ApiModelProperty替換為openapi3對(duì)應(yīng)的注解:@Tag、@Operation、 @Parameter、 @Schema、 @SchemaProperty

最后將swagger的配置類(lèi)內(nèi)容由

    @Bean(value = "oasConfig")
    public Docket oasConfig() {
        Docket docket=new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(new ApiInfoBuilder()
                        .title("spring-project-framework")
                        .description("spring項(xiàng)目骨架")
                        .version("v1")
                        .build())
                .groupName("backup-v1")
                .select()
                .apis(RequestHandlerSelectors.basePackage("movee.api.v1"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

改為:

    @Bean(value = "oasConfig")
    public GroupedOpenApi oasConfig(){
        return GroupedOpenApi.builder()
                .group("spring-project-framework-v1")
                .addOpenApiCustomizer(api -> api.info(new Info()
                        .title("spring-project-framework")
                        .description("spring項(xiàng)目骨架")
                        .version("v1")))
                .packagesToScan("movee.api.v1")
                .build();
    }

修改完后,重新編譯啟動(dòng),這次能正常啟動(dòng)了

但是web訪(fǎng)問(wèn)項(xiàng)目接口時(shí)報(bào)以下錯(cuò)誤:

Caused by: java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
    at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:516)
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:538)
    at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1275)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1057)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
    ... 36 common frames omitted

這個(gè)是跨域的問(wèn)題,新版本spring MVC的CorsRegistry已經(jīng)沒(méi)有allowedOrigin() 方法了,替換為新接口allowedOriginPatterns()即可,代碼示例如下:

@Configuration
public class WebCorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("*");
    }
}

這時(shí)因?yàn)橹绊?xiàng)目的spring cloudactuator的相關(guān)配置寫(xiě)在bootstrap.yml文件中,升級(jí)到spring boot 3之后actuator的端點(diǎn)(如/actuator/info等)無(wú)法訪(fǎng)問(wèn),要想啟動(dòng)時(shí)系統(tǒng)讀取bootstrap.yml中的配置,使bootstrap.yml文件中的配置生效,需要在項(xiàng)目的pom.xml文件中添加下面的依賴(lài):

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
    </dependencies>

到此升級(jí)完成!

3 更進(jìn)一步

之前項(xiàng)目中使用的GC收集器是CMS收集器,CMS收集器的調(diào)參非常繁瑣,非??简?yàn)工程師的功底。ZGC聲稱(chēng)能保證8MB~16TB的堆內(nèi)存范圍內(nèi)都能保證GC的停頓時(shí)間在毫秒(官方聲稱(chēng)小于10ms,也有些文章表示實(shí)際只有1、2ms)級(jí)別,尤其是一般情況下只要設(shè)置幾個(gè)基本的GC參數(shù)就能讓GC收集器很好的工作了,簡(jiǎn)直是工程師的福音。隨著ZGC在JDK 15中正式GA,趁著升級(jí)JDK 17的機(jī)會(huì)立即把ZGC用起來(lái)。 設(shè)置幾個(gè)基本的ZGC參數(shù):

# log
JVM_OPTS="$JVM_OPTS -XX:+PrintCommandLineFlags"
JVM_OPTS="$JVM_OPTS -Xlog:gc*:file=${LOG_DIR}/${PROJ_NAME}-gc-%p.log:time,uptime:filecount=10,filesize=50M"
JVM_OPTS="$JVM_OPTS -XX:+HeapDumpOnOutOfMemoryError"
JVM_OPTS="$JVM_OPTS -XX:HeapDumpPath=${LOG_DIR}/${PROJ_NAME}-`date +%s`-pid$$.hprof"
JVM_OPTS="$JVM_OPTS -XX:ErrorFile=${LOG_DIR}/${PROJ_NAME}-`date +%s`-pid%p.log"
# memory
JVM_OPTS="$JVM_OPTS -Xms4g"
JVM_OPTS="$JVM_OPTS -Xmx4g"
JVM_OPTS="$JVM_OPTS --add-opens=java.base/java.lang=ALL-UNNAMED"
JVM_OPTS="$JVM_OPTS --add-opens=java.base/java.util=ALL-UNNAMED"
JVM_OPTS="$JVM_OPTS --add-exports=java.base/sun.security.ssl=ALL-UNNAMED"
JVM_OPTS="$JVM_OPTS --add-opens=java.base/sun.security.ssl.internal.ssl=ALL-UNNAMED"
# gc collector
JVM_OPTS="$JVM_OPTS -XX:+UseZGC"
# JVM_OPTS="$JVM_OPTS -XX:ConcGCThreads=4"
JVM_OPTS="$JVM_OPTS -XX:+UnlockDiagnosticVMOptions"
JVM_OPTS="$JVM_OPTS -XX:ZStatisticsInterval=10"

總結(jié)

到此這篇關(guān)于JDK8升級(jí)JDK17過(guò)程中踩到的一些坑的文章就介紹到這了,更多相關(guān)JDK8升級(jí)JDK17踩坑內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解java中的深拷貝和淺拷貝(clone()方法的重寫(xiě)、使用序列化實(shí)現(xiàn)真正的深拷貝)

    詳解java中的深拷貝和淺拷貝(clone()方法的重寫(xiě)、使用序列化實(shí)現(xiàn)真正的深拷貝)

    這篇文章主要介紹了java中的深拷貝和淺拷貝(clone()方法的重寫(xiě)、使用序列化實(shí)現(xiàn)真正的深拷貝),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • SpringDataJpa多表操作的實(shí)現(xiàn)

    SpringDataJpa多表操作的實(shí)現(xiàn)

    開(kāi)發(fā)過(guò)程中會(huì)有很多多表的操作,他們之間有著各種關(guān)系,本文主要介紹了SpringDataJpa多表操作的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Java中equals方法使用及重寫(xiě)練習(xí)

    Java中equals方法使用及重寫(xiě)練習(xí)

    equals是在object類(lèi)中的方法,在object中equals是用來(lái)看看兩個(gè)參數(shù)是否引用的是同一個(gè)對(duì)象,下面這篇文章主要給大家介紹了關(guān)于Java中equals方法使用及重寫(xiě)練習(xí)的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • java字符串轉(zhuǎn)JSON簡(jiǎn)單代碼示例

    java字符串轉(zhuǎn)JSON簡(jiǎn)單代碼示例

    這篇文章主要給大家介紹了關(guān)于java字符串轉(zhuǎn)JSON的相關(guān)資料,JSON?是一種輕量級(jí)的數(shù)據(jù)交換格式,常用于Web應(yīng)用程序中的數(shù)據(jù)傳輸,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • Java char[]數(shù)組轉(zhuǎn)成String類(lèi)型詳細(xì)介紹

    Java char[]數(shù)組轉(zhuǎn)成String類(lèi)型詳細(xì)介紹

    這篇文章詳細(xì)介紹了Java char[]數(shù)組轉(zhuǎn)成String類(lèi)型(char to String)的方法,文章中有詳細(xì)的代碼示例,需要的朋友可以參考閱讀
    2023-04-04
  • Android實(shí)現(xiàn)兼容的水波紋效果

    Android實(shí)現(xiàn)兼容的水波紋效果

    Android的水波紋效果只有高版本才有,我們希望自己的應(yīng)用在低版本用低版本的陰影,而高版本用水波紋,這怎么做呢?下面一起來(lái)學(xué)習(xí)學(xué)習(xí)。
    2016-08-08
  • 一文讀懂IDEA里面的Artifact到底是什么

    一文讀懂IDEA里面的Artifact到底是什么

    這篇文章主要介紹了IDEA里面的Artifact到底是什么,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-01-01
  • cxf整合Spring實(shí)現(xiàn)webservice調(diào)用實(shí)踐

    cxf整合Spring實(shí)現(xiàn)webservice調(diào)用實(shí)踐

    文章介紹了使用CXF整合Spring實(shí)現(xiàn)WebService的過(guò)程,包括pom文件配置、web.xml和applicationContext.xml文件配置、接口定義與實(shí)現(xiàn)、項(xiàng)目運(yùn)行及測(cè)試,通過(guò)訪(fǎng)問(wèn)wsdl地址驗(yàn)證服務(wù)可用性,最后通過(guò)客戶(hù)端測(cè)試類(lèi)驗(yàn)證調(diào)用成功
    2026-04-04
  • 在mybatis執(zhí)行SQL語(yǔ)句之前進(jìn)行攔擊處理實(shí)例

    在mybatis執(zhí)行SQL語(yǔ)句之前進(jìn)行攔擊處理實(shí)例

    本篇文章主要介紹了在mybatis執(zhí)行SQL語(yǔ)句之前進(jìn)行攔擊處理實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • Java基礎(chǔ)知識(shí)精通數(shù)組的內(nèi)存分析

    Java基礎(chǔ)知識(shí)精通數(shù)組的內(nèi)存分析

    數(shù)組對(duì)于每一門(mén)編程語(yǔ)言來(lái)說(shuō)都是重要的數(shù)據(jù)結(jié)構(gòu)之一,當(dāng)然不同語(yǔ)言對(duì)數(shù)組的實(shí)現(xiàn)及處理也不盡相同。Java?語(yǔ)言中提供的數(shù)組是用來(lái)存儲(chǔ)固定大小的同類(lèi)型元素
    2022-04-04

最新評(píng)論

武邑县| 保定市| 华宁县| 贵南县| 阜阳市| 德清县| 鲁甸县| 遂宁市| 定日县| 英吉沙县| 永宁县| 当雄县| 衡阳市| 泗水县| 运城市| 广德县| 乐山市| 阳东县| 胶南市| 巴东县| 镇远县| 宝应县| 宁陵县| 云梦县| 武义县| 垦利县| 铅山县| 威信县| 松阳县| 富宁县| 墨江| 昌乐县| 喀喇沁旗| 甘谷县| 保靖县| 儋州市| 浦城县| 文水县| 龙井市| 醴陵市| 白玉县|