OpenJDK11与Spring Cloud Finchley的不兼容问题与解决

Stella981
• 阅读 900

本文的环境:OpenJDK 11.0.4,Spring Cloud finchley SR4,Spring Boot 2.0.3

最近遇到了一个问题,在feign调用的时候,时常会出现这样一个奇怪的错误:

2019-10-07 08:00:00.620 ERROR [xxx,e1ba4c7540954aa3,871b99c4576d42e3] [24] [XNIO-2 task-286][xxx:83]: URI:[/xxx], method:[PUT], 500Exception: class com.netflix.hystrix.exception.HystrixRuntimeException, xxxxx#xxxx(xxx) failed and no fallback available.

com.netflix.hystrix.exception.HystrixRuntimeException: xxxxx#xxxx(xxx)  failed and no fallback available.
        at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:822) ~[hystrix-core-1.5.18.jar!/:1.5.18]
        at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:807) ~[hystrix-core-1.5.18.jar!/:1.5.18]
        at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:140) ~[rxjava-1.3.8.jar!/:1.3.8]
省略无用堆栈
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration]; nested exception is java.io.FileNotFoundException: class path resource [org/springframework/boot/context/properties/EnableConfigurationPropertiesImportSelector$ConfigurationPropertiesBeanRegistrar.class] cannot be opened because it does not exist
        at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:646) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:303) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:245) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:202) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:170) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:316) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:233) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:271) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:91) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533) ~[spring-context-5.0.13.RELEASE.jar!/:5.0.13.RELEASE]
        at org.springframework.cloud.context.named.NamedContextFactory.createContext(NamedContextFactory.java:117) ~[spring-cloud-context-2.0.3.RELEASE.jar!/:2.0.3.RELEASE]
        at org.springframework.cloud.context.named.NamedContextFactory.getContext(NamedContextFactory.java:85) ~[spring-cloud-context-2.0.3.RELEASE.jar!/:2.0.3.RELEASE]
        at org.springframework.cloud.netflix.ribbon.SpringClientFactory.getContext(SpringClientFactory.java:118) ~[spring-cloud-netflix-ribbon-2.0.3.RELEASE.jar!/:2.0.3.RELEASE]
        at org.springframework.cloud.context.named.NamedContextFactory.getInstance(NamedContextFactory.java:126) ~[spring-cloud-context-2.0.3.RELEASE.jar!/:2.0.3.RELEASE]
        at org.springframework.cloud.netflix.ribbon.SpringClientFactory.getInstance(SpringClientFactory.java:108) ~[spring-cloud-netflix-ribbon-2.0.3.RELEASE.jar!/:2.0.3.RELEASE]

这个错误很奇怪,只要重新编译发布,就不会再出现。这个很有可能是打包问题,还有类加载问题。

查询github上,社区的人说是类加载问题(https://github.com/spring-cloud/spring-cloud-netflix/issues/3101#issuecomment-463382093),首先对于OpenJDK,曾经有一个Bug(https://bugs.openjdk.java.net/browse/JDK-8172726): 对于ParallelStream,我们知道默认是由JDK启动时默认启动的大小为CPU核数减1的CommonForkJoinPool执行。在多线程多类加载器环境下,这个CommonForkJoinPool可能会有Bug,就是调用Thread.contextClassLoader的时候,返回的是第一个使用CommonForkJoinPool的代码的Classloader,而不是系统根ClassLoader,这样会导致类找不到。

社区修复了这个Bug,只不过是在下一个大版本,也就是GreenWich上,对于Finchley,并没有修复。

我们考虑两种解决方案:

  1. 升级到GreenWich,这个改动很大,从Finchley到GreenWich,Bean初始化机制,JDBC连接池,等等都有了很多变化,短期内耗时费力。

  2. 参考:https://github.com/spring-cloud/spring-cloud-commons/commit/b38ce54410af8fc62d8ae6fe694b580e509ae73a#diff-8c70f107deac71db815f81fa81d5f947,覆盖源码,修改org.springframework.cloud.context.named.NamedContextFactory:

    protected AnnotationConfigApplicationContext createContext(String name) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); if (this.configurations.containsKey(name)) { for (Class configuration : this.configurations.get(name) .getConfiguration()) { context.register(configuration); } } for (Map.Entry entry : this.configurations.entrySet()) { if (entry.getKey().startsWith("default.")) { for (Class configuration : entry.getValue().getConfiguration()) { context.register(configuration); } } } context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType); context.getEnvironment().getPropertySources().addFirst(new MapPropertySource( this.propertySourceName, Collections.<String, Object> singletonMap(this.propertyName, name))); if (this.parent != null) { // Uses Environment from parent as well as beans context.setParent(this.parent); //在这里添加代码,使用parent的类加载器 context.setClassLoader(this.parent.getClassLoader()); } context.setDisplayName(generateDisplayName(name)); context.refresh(); return context; }

这样也是一种应急方案,短期内解决问题。留足时间升级。

点赞
收藏
评论区
推荐文章
梦
3年前
微信小程序new Date()转换时间异常问题
微信小程序苹果手机页面上显示时间异常,安卓机正常问题image(https://imghelloworld.osscnbeijing.aliyuncs.com/imgs/b691e1230e2f15efbd81fe11ef734d4f.png)错误代码vardate'2021030617:00:00'vardateT
Wesley13 Wesley13
3年前
SQL利用函数或存储过程求男或女的总分平均分
!(https://oscimg.oschina.net/oscnet/633e11621f3e13e713cf063db00d72c8aa0.png)函数alterfunctionxb(@xingbievarchar(2))returnstableas
Easter79 Easter79
3年前
springboot的起步依赖
!(https://oscimg.oschina.net/oscnet/f3acbe4cf3b00c68207e091c172d6b45a27.png)加载自动配置的方式2:!(https://oscimg.oschina.net/oscnet/40341228c10f7a56d82323a1d622521d92d.png) spring
Easter79 Easter79
3年前
swing 聊天窗体,支持图文模式
!(https://oscimg.oschina.net/oscnet/7bffe1e627c0dcd84aee04edb6b80f00c94.jpg)!(https://oscimg.oschina.net/oscnet/3cf62b9e5426e6a259ad3c137f795a5ba7c.jpg)packagecom..tes
Stella981 Stella981
3年前
Dubbo 扩展点加载机制:从 Java SPI 到 Dubbo SPI
!(https://oscimg.oschina.net/oscnet/up1aa4ada0efc8a144d35d25b3443d951c7e3.JPEG)SPI全称为ServiceProviderInterface,是一种服务发现机制。当程序运行调用接口时,会根据配置文件或默认规则信息加载对应的实现类。所以在程序中并没有直接指定使用接口
Stella981 Stella981
3年前
Feign请求响应结果被截取com.fasterxml.jackson.core.io.JsonEOFException
在生产环境使用feign调用外部接口时,偶尔会出现下面错误2020101511:00:18,535ERRORcom.shein.abc.rmp.controller.RecExplainConfigControllerrec_explain_query.failffeign.codec.DecodeExc
Stella981 Stella981
3年前
Spring Boot日志集成
!(https://oscimg.oschina.net/oscnet/1bde8e8d00e848be8b84e9d1d44c9e5c.jpg)SpringBoot日志框架SpringBoot支持JavaUtilLogging,Log4j2,Lockback作为日志框架,如果你使用star
Stella981 Stella981
3年前
Nginx反向代理upstream模块介绍
!(https://oscimg.oschina.net/oscnet/1e67c46e359a4d6c8f36b590a372961f.gif)!(https://oscimg.oschina.net/oscnet/819eda5e7de54c23b54b04cfc00d3206.jpg)1.Nginx反
Stella981 Stella981
3年前
AI 科学家带你快速 Get 人工智能最热技术
!(https://pic3.zhimg.com/80/v2af9f6637b50b09be60b00a42f3812d5e_1440w.jpg)日前,京东智联云与贪心学院联合举办的人工智能前沿技
Stella981 Stella981
3年前
Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法
Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法参考文章:(1)Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.codeprj.com%2Fblo