Could not find class [org.springframework.boot.autoconfigure.condition.OnPropertyCondition]

目录

1、异常信息

2、异常代码实现(优化前)

3、原因分析

4、本文解决方案

5、其它解决方案

6、小结


        最近做一个导出聊天记录的需求,为了提高接口响应速度,我便使用CompletableFuture开启两个线程,一个下载文件,另一个生成PDF,两个线程都执行完成再压缩返回;本来一切顺利推进,但线上环境一个偶然出现的异常信息引起了我的注意,奇怪的是在本地调试没有遇到过,而且此异常的触发条件是在线上打包部署后第一次调用此接口才有几率复现这个问题;emm........mmp,原本想睁一只眼闭一只眼不管这个问题,我不说测试也不一定能发现对吧;可惜我是有点强迫症的,怎么能允许自己的接口有一丁点的瑕疵呢,誓与bug不共戴天,于是一场艰难的战斗打响了...

1、异常信息

2022-10-17 20:18:06,949 [TID: N/A] [ERROR] [sendMessage-0] c.z.r.s.NewRocketApiService [NewRocketApiService.java : 346] fileTask exception:
java.util.concurrent.CompletionException: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Could not find class [org.springframework.boot.autoconfigure.condition.OnPropertyCondition]
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
	at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1739)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Could not find class [org.springframework.boot.autoconfigure.condition.OnPropertyCondition]
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:600)
	at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:678)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:737)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
	at com.zzw.redops.service.NewRocketApiService.lambda$exportChatRecords$6(NewRocketApiService.java:328)
	at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736)
	... 3 common frames omitted
Caused by: java.lang.IllegalArgumentException: Could not find class [org.springframework.boot.autoconfigure.condition.OnPropertyCondition]
	at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:334)
	at org.springframework.context.annotation.ConditionEvaluator.getCondition(ConditionEvaluator.java:124)
	at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:96)
	at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:88)
	at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:71)
	at org.springframework.context.annotation.AnnotatedBeanDefinitionReader.doRegisterBean(AnnotatedBeanDefinitionReader.java:254)
	at org.springframework.context.annotation.AnnotatedBeanDefinitionReader.registerBean(AnnotatedBeanDefinitionReader.java:147)
	at org.springframework.context.annotation.AnnotatedBeanDefinitionReader.register(AnnotatedBeanDefinitionReader.java:137)
	at org.springframework.context.annotation.AnnotationConfigApplicationContext.register(AnnotationConfigApplicationContext.java:162)
	at org.springframework.cloud.context.named.NamedContextFactory.createContext(NamedContextFactory.java:120)
	at org.springframework.cloud.context.named.NamedContextFactory.getContext(NamedContextFactory.java:102)
	at org.springframework.cloud.netflix.ribbon.SpringClientFactory.getContext(SpringClientFactory.java:131)
	at org.springframework.cloud.context.named.NamedContextFactory.getInstance(NamedContextFactory.java:146)
	at org.springframework.cloud.netflix.ribbon.SpringClientFactory.getInstance(SpringClientFactory.java:121)
	at org.springframework.cloud.netflix.ribbon.SpringClientFactory.getClientConfig(SpringClientFactory.java:75)
	at org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.getClientConfig(LoadBalancerFeignClient.java:98)
	at org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:82)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:119)
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:89)
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100)
	at com.sun.proxy.$Proxy189.getObjectFile(Unknown Source)
	at com.zzw.redops.service.NewRocketApiService.lambda$null$5(NewRocketApiService.java:334)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.autoconfigure.condition.OnPropertyCondition
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:398)
	at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
	at org.springframework.util.ClassUtils.resolveClassName(ClassUtils.java:324)
	... 31 common frames omitted

2、异常代码实现(优化前)

CompletableFuture<Void> fileTask = CompletableFuture.runAsync(() -> {
			recordsVOList.parallelStream().filter(item-> RocketConstants.MESSAGE_TYPE_FILE.equals(item.getType())).forEach(item->{
				JSONObject jsonObject = JSONObject.parseObject(item.getMsg());
				String fileName = jsonObject.getString("fileName");
				String fileURI = jsonObject.getString("fileURI");
				String objectName = fileURI.substring(fileURI.lastIndexOf("/") + 1);
				Response res = ossClient.getObjectFile("redops-test", objectName);
				File downloadFile = new File("downloadFile/"+fileName);
				try {
					FileUtils.copyInputStreamToFile(res.body().asInputStream(), downloadFile);
				} catch (IOException e) {
					log.error("copyInputStreamToFile exception:",e);
				}
				files.add(downloadFile);
			});
			log.info("文件完成");
		}, threadPool).exceptionally(e->{
			log.error("fileTask exception:",e);
			return null;
		});

3、原因分析

        找了许久也没找到适用的解决方案,最终在GitHub的开源项目spring-cloud-openfeign中看到了相似问题的描述,我从中的理解是由于在异步任务中使用并行流通过openfeign调用其它模块的接口造成,可能是本身就存在这个问题,原文如下

原文链接:`ClassNotFoundException` when calling a `FeignBlockingLoadBalancerClient` in a parallel stream (multiple threads) · Issue #600 · spring-cloud/spring-cloud-openfeign · GitHubDescribe the bug When calling a @FeignClient (FeignBlockingLoadBalancerClient) in a parallel stream (stream.parallel()), the following error arises, only when executing it as an uber/executable jar. It seems to be related (kind of) to so...https://github.com/spring-cloud/spring-cloud-openfeign/issues/600

原文链接:https://github.com/spring-cloud/spring-cloud-openfeign/issues/475

官方维护团队不建议使用此种写法,这个问题并未关闭,维护团队并未给出好的解决方案

 4、本文解决方案

        原本使用的是并行流下载文件,现改为串行流,问题解决

CompletableFuture<Void> fileTask = CompletableFuture.runAsync(() -> {
			recordsVOList.stream().filter(item-> RocketConstants.MESSAGE_TYPE_FILE.equals(item.getType())).forEach(item->{
				JSONObject jsonObject = JSONObject.parseObject(item.getMsg());
				String fileName = jsonObject.getString("fileName");
				String fileURI = jsonObject.getString("fileURI");
				String objectName = fileURI.substring(fileURI.lastIndexOf("/") + 1);
				Response res = ossClient.getObjectFile("redops-test", objectName);
				File downloadFile = new File("downloadFile/"+fileName);
				try {
					FileUtils.copyInputStreamToFile(res.body().asInputStream(), downloadFile);
				} catch (IOException e) {
					log.error("copyInputStreamToFile exception:",e);
				}
				files.add(downloadFile);
			});
			log.info("文件完成");
		}, threadPool).exceptionally(e->{
			log.error("fileTask exception:",e);
			return null;
		});

5、其它解决方案

        自定义LoadBalancerClientFactory

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    <version>3.1.1</version>
</dependency>
@Bean
@ConditionalOnMissingBean
public LoadBalancerClientFactory loadBalancerClientFactory(ObjectProvider<List<LoadBalancerClientSpecification>> configurations) {
    LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory(){            
        @Override
        protected AnnotationConfigApplicationContext createContext(String name) {
            // FIXME: temporary switch classloader to use the correct one when creating the 		   context
            ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
            AnnotationConfigApplicationContext context = super.createContext(name);
            Thread.currentThread().setContextClassLoader(originalClassLoader);
            return context;
        }
    };
    clientFactory.setConfigurations(configurations.getIfAvailable(Collections::emptyList));
    return clientFactory;
}

6、小结

        博主实力有限,暂时没有能力深究其中的原因,大家可根据实际情况尝试使用本文中的方法看是否有效;大家也可关注spring-cloud-openfeign官方维护团队的动态,看官方给出什么样的解决方案,说不定在新的版本中就解决了

        有任何问题,欢迎大家指正!

        转载请注明出处!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值