一、现象
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'feignTargeter' defined in class path resource [org/springframework/cloud/openfeign/FeignAutoConfiguration$HystrixFeignTargeterConfiguration.class]: Initialization of bean failed; nested exception is java.lang.IllegalAccessError: class org.springframework.cloud.openfeign.$Proxy109 cannot access its superinterface org.springframework.cloud.openfeign.Targeter
at com.alibaba.cloud.dubbo.openfeign.TargeterBeanPostProcessor.postProcessAfterInitialization(TargeterBeanPostProcessor.java:75)
原始日志:
2021-02-09 00:02:23,908 ERROR [restartedMain] 14833 org.springframework.boot.SpringApplication[823]: Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'feignTargeter' defined in class path resource [org/springframework/cloud/openfeign/FeignAutoConfiguration$HystrixFeignTargeterConfiguration.class]: Initialization of bean failed; nested exception is java.lang.IllegalAccessError: class org.springframework.cloud.openfeign.$Proxy109 cannot access its superinterface org.springframework.cloud.openfeign.Targeterat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$146/410686727.getObject(Unknown Source)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:847)at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)at org.springframework.boot.SpringApplication.run(SpringApplication.java:1204)at com.mk.springcloud.dubbo.provider.UserProviderApplication.main(UserProviderApplication.java:13)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:497)at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.IllegalAccessError: class org.springframework.cloud.openfeign.$Proxy109 cannot access its superinterface org.springframework.cloud.openfeign.Targeterat java.lang.reflect.Proxy.defineClass0(Native Method)at java.lang.reflect.Proxy.access$300(Proxy.java:228)at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:642)at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:557)at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230)at java.lang.reflect.WeakCache.get(WeakCache.java:127)at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:419)at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:719)at com.alibaba.cloud.dubbo.openfeign.TargeterBeanPostProcessor.postProcessAfterInitialization(TargeterBeanPostProcessor.java:75)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:429)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)... 21 common frames omitted
(1)maven设置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.9.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.mk.springcloud</groupId><artifactId>springcloud-nacos-dubbo</artifactId><version>1.0.0</version><packaging>pom</packaging><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2.1.3.RELEASE</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-dubbo</artifactId><version>2.1.3.RELEASE</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.1.3.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><modules><module>dubbo-interface</module><module>user-provider</module><module>class-provider</module><module>dubbo-consumer</module><module>micro-service</module><module>zuul-gateway</module><module>springcloud-gateway</module></modules><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>
(2)FeignAutoConfiguration的feignTargeter创建类
@Configuration
@ConditionalOnClass({Feign.class})
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {@Configuration@ConditionalOnClass(name = {"feign.hystrix.HystrixFeign"})protected static class HystrixFeignTargeterConfiguration {protected HystrixFeignTargeterConfiguration() {}@Bean@ConditionalOnMissingBeanpublic Targeter feignTargeter() {return new HystrixTargeter();}}
}
(3)TargeterBeanPostProcessor.postProcessAfterInitialization方法
public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLoaderAware {private final Environment environment;private final DubboServiceMetadataRepository dubboServiceMetadataRepository;private final DubboGenericServiceFactory dubboGenericServiceFactory;private final DubboGenericServiceExecutionContextFactory contextFactory;private ClassLoader classLoader;public TargeterBeanPostProcessor(Environment environment, DubboServiceMetadataRepository dubboServiceMetadataRepository, DubboGenericServiceFactory dubboGenericServiceFactory, DubboGenericServiceExecutionContextFactory contextFactory) {this.environment = environment;this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;this.dubboGenericServiceFactory = dubboGenericServiceFactory;this.contextFactory = contextFactory;}public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {if (ClassUtils.isPresent("org.springframework.cloud.openfeign.Targeter", this.classLoader)) {Class<?> beanClass = ClassUtils.getUserClass(bean.getClass());Class<?> targetClass = ClassUtils.resolveClassName("org.springframework.cloud.openfeign.Targeter", this.classLoader);if (targetClass.isAssignableFrom(beanClass)) {return Proxy.newProxyInstance(this.classLoader, new Class[]{targetClass}, new TargeterInvocationHandler(bean, this.environment, this.classLoader, this.dubboServiceMetadataRepository, this.dubboGenericServiceFactory, this.contextFactory));}}return bean;}public void setBeanClassLoader(ClassLoader classLoader) {this.classLoader = classLoader;}
}
二、分析原因
(1)排除openfeign-core依赖包和spring-cloud-starter-openfeign启动正常
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-dubbo</artifactId><version>2.1.3.RELEASE</version><exclusions><exclusion><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-openfeign-core</artifactId></exclusion></exclusions>
</dependency><!--<dependency>--><!--<groupId>org.springframework.cloud</groupId>--><!--<artifactId>spring-cloud-starter-openfeign</artifactId>--><!--<version>2.1.3.RELEASE</version>-->
<!--</dependency>-->
(2)SpringBootApplication排除FeignAutoConfiguration也启动正常
@EnableDiscoveryClient
@SpringBootApplication(exclude = FeignAutoConfiguration.class)
public class UserProviderApplication {public static void main(String[] args) {SpringApplication.run(UserProviderApplication.class, args);}}
(3)debug发现beanClass.getClassLoader()和classLoader不一致造成类访问不了
(4)找出起因
看到RestartClassLoader就猜想到IDEA的agent和springboot的热发布,从classLoader对象找到了包信息。如下:
ProtectionDomain (null <no signer certificates>)
org.springframework.boot.devtools.restart.classloader.RestartClassLoader@bc8c9ff
是springboot的热发布包造成的,去掉spring-boot-devtools则能够正常启动。
(5)拓展
官方说明 官方文档 :
By default, any open project in your IDE will be loaded using the “restart” classloader, and any regular .jar file will be loaded using the “base” classloader. If you work on a multi-module project, and not each module is imported into your IDE, you may need to customize things. To do this you can create a META-INF/spring-devtools.properties file.
翻译:
默认情况下,IDE中打开的项目文件都会使用devtools的restart加载器,但是三方的jar文件则会被系统默认的加载器加载。如果你涉及多模块开发的时候需要把每一个模块在IDE打开,你需要指定加载器的时候,在META/INF下创建一个spring-devtools.properties。
三、解决方法
(1)去掉热部署包spring-boot-devtools
(2)拦截bean修改TargeterBeanPostProcessor.postProcessAfterInitialization方法
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {if (ClassUtils.isPresent("org.springframework.cloud.openfeign.Targeter", this.classLoader)) {Class<?> beanClass = ClassUtils.getUserClass(bean.getClass());Class<?> targetClass = ClassUtils.resolveClassName("org.springframework.cloud.openfeign.Targeter", this.classLoader);if (targetClass.isAssignableFrom(beanClass)) {return Proxy.newProxyInstance(beanClass.getClassLoader(), new Class[]{targetClass}, new TargeterInvocationHandler(bean, this.environment, beanClass.getClassLoader(), this.dubboServiceMetadataRepository, this.dubboGenericServiceFactory, this.contextFactory));}}return bean;}