本文的環境:OpenJDK 11.0.4,Spring Cloud finchley SR4,Spring Boot 2.0.3java
最近遇到了一個問題,在feign調用的時候,時常會出現這樣一個奇怪的錯誤:git
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
查詢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,這樣會致使類找不到。spring
社區修復了這個Bug,只不過是在下一個大版本,也就是GreenWich上,對於Finchley,並無修復。多線程
咱們考慮兩種解決方案:post
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<String, C> 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; }
這樣也是一種應急方案,短時間內解決問題。留足時間升級。this