一、问题描述
spring boot多模块项目,其中的某个模块,使用proguard混淆之后,在主模块里,引入,启动就报如下错误:
19:46:30.729 [main] ERROR o.s.b.SpringApplication - [reportFailure,860] - Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jobHandlerBeanPostProcessor' defined in class path resource [com/xxx/xxx/xxx/config/xxxxJobAutoConfiguration.class]: Unsatisfied dependency expressed through method 'jobHandlerBeanPostProcessor' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.xxx.xxx.xxx.service.LesseeFrameworkService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {
}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:270)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:567)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:771)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:763)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:339)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:144)
at com.xxx.xxx.modules.admin.AdminStartApplication.execute(AdminStartApplication.java:220)
at com.xxx.xxx.modules.admin.AdminStartApplication.start(AdminStartApplication.java:125)
at com.xxx.xxx.modules.admin.AdminStartApplication.main(AdminStartApplication.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.xxx.xxx.xxx.service.LesseeFrameworkService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {
}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1790)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
... 29 common frames omitted
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jobHandlerBeanPostProcessor' defined in class path resource [com/xxx/xxx/xxx/config/xxxxJobAutoConfiguration.class]: Unsatisfied dependency expressed through method 'jobHandlerBeanPostProcessor' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.xxx.xxx.xxx.xxx.service.LesseeFrameworkService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {
}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:270)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:567)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:771)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:763)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:339)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:144)
at com.xxx.xxx.modules.admin.AdminStartApplication.execute(AdminStartApplication.java:220)
at com.xxx.xxx.modules.admin.AdminStartApplication.start(AdminStartApplication.java:125)
at com.xxx.xxx.modules.admin.AdminStartApplication.main(AdminStartApplication.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.xxx.xxx.xxx.service.LesseeFrameworkService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {
}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1790)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
NoSuchBeanDefinitionException,UnsatisfiedDependencyException 这种错误不就是注入失败,没有找到相关的bean,才会报错
二、解决方法
,事后解决之后,总结如下,可按如下步骤排查:
1.spring 相关的注解,不要混淆,一旦混淆,很容易出现这种情况,配置如下选项:
# 不混淆所有特殊的类:对异常、注解信息在runtime予以保留,不然影响springboot启动
-keepattributes Exceptions,InnerClasses,Signature?Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,SyntheticjEnclosingMethod
-keepclassmembers class * {
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Qualifier *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.beans.factory.annotation.Required *;
@org.springframework.context.annotation.Bean *;
@org.springframework.context.annotation.Primary *;
@org.springframework.boot.context.properties.ConfigurationProperties *;
@org.springframework.boot.context.properties.EnableConfigurationProperties *;
@javax.inject.Inject *;
@javax.annotation.PostConstruct *;
@javax.annotation.PreDestroy *;
}
-keepclassmembers class * {
@org.springframework.beans.factory.annotation.Autowired <fields>;
@org.springframework.beans.factory.annotation.Autowired <methods>;
@org.springframework.security.access.prepost.PreAuthorize <methods>;
}
2.混淆之后,确认你的包名是否被改了,改了需要添加进去
@ComponentScan(value = {
"com.xxx","xxx.xxx.xxx"})
3.jar的问题,proguard需要保持目录结构
#保持目录结构
-keepdirectories
否则会出现,通过如下方式会获取为空:
this.getClassLoader("com/xxxx/xxx")
我这里报错就是出在这,打包出来的\BOOT-INF\lib目录下,明明存在依赖的jar,class文件也存在,就是报上面的错误,从日志堆栈信息,结合源码,发现在org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider类中的scanCandidateComponents里
将配置的包名,转换成路径的形式,去classpath*:下找,在421行,死活找不到报错那个bean的jar包,将该代码复制出来,新建测试类:
//获取Spring资源解析器
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
//获取packageSearchPath下的Resource,这里得到的Resource是Class信息
Resource[] resources = resourcePatternResolver.getResources("com.xxx.xxx"
+ ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage))
+ DEFAULT_RESOURCE_PATTERN + ClassUtils.CLASS_FILE_SUFFIX);
Arrays.stream(resources).forEach(resource -> {
System.out.println("=======>" + resource.getFilename());
});
获取也为空,使用ClassGraph,通过包名的形式又能获取到
try (ScanResult scanResult = new ClassGraph().acceptPackages("com.xxx.xxx.xxx").scan()) {
scanResult.getAllResources().forEachByteArrayIgnoringIOException((io.github.classgraph.Resource res, byte[] content) -> {
String path = res.getPath();
System.out.println("文件:" + path);
});
}
一步一步测试,手动解压jar包,然后又通过jar命令打包jar
jar -cfM0 xxx.jar .
从新打包的又可以,确定是jar包的原因,怀疑可能是jar包目录有问题,通过压缩软件查看貌似没有问题,然后又通过如下代码打印jar包目录,也没发现有啥问题
JarFile startJarFile = new JarFile("E:\\xxx\\start-1.0-SNAPSHOT.jar");
Enumeration<JarEntry> startJarEntrys = startJarFile.entries();
while (startJarEntrys.hasMoreElements()) {
JarEntry entry = startJarEntrys.nextElement();
System.out.println("startJarEntrys:" + entry.getName());
}
去网上找了下jar包格式。。。都是介绍MAINFEST.MF文件相关的。。最后通过7zip命令,查出来,确实是jar包的目录有问题:
7z l xxxx.jar
错误的jar包目录:
正确的jar包目录: