記遇見的一次AbstractMethodError


問題:

  • Spring Cloud Version:Hoxton.SR3
  • Spring Cloud Alibaba Version:2.2.0.RELEASE

項目中consumer端使用@FeignClient定義接口,啟動報錯:

Caused by: java.lang.AbstractMethodError: com.alibaba.cloud.sentinel.feign.SentinelContractHolder.parseAndValidateMetadata(Ljava/lang/Class;)Ljava/util/List;
	at feign.ReflectiveFeign$ParseHandlersByName.apply(ReflectiveFeign.java:151) ~[feign-core-10.7.4.jar:na]
	at feign.ReflectiveFeign.newInstance(ReflectiveFeign.java:49) ~[feign-core-10.7.4.jar:na]

分析:

Spring Cloud從Hoxton.SR1版本開始,依賴的spring-cloud-starter-openfeign版本為2.2.2.RELEASE;
Spring Cloud Alibaba 2.2.0.RELEASE依賴的spring-cloud-openfeign-dependencies版本為2.2.0.RELEASE;

feign的Contract接口,
2.2.0.RELEASE:

// TODO: break this and correct spelling at some point
List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType);

2.2.2.RELEASE:

List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType);

在2.2.0.RELEASE里有一行注釋描述,接口方法名拼寫錯誤,在2.2.2.RELEASE方法已修正了,即方法名發生了改變。

spring-cloud-alibaba-sentinel中的SentinelContractHolder類,用到了該接口的這個方法(feign2.2.0.RELEASE版本):

@Override
public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
	List<MethodMetadata> metadatas = delegate.parseAndValidatateMetadata(targetType);
	metadatas.forEach(metadata -> METADATA_MAP
			.put(targetType.getName() + metadata.configKey(), metadata));
	return metadatas;
}

解決:

以下3中方式均可:

  • 修改Spring Cloud版本,Hoxton.SR3改為Hoxton.RELEASE

  • 在dependencyManagement中指定spring-cloud-openfeign-dependencies的版本為2.2.0.RELEASE

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-openfeign-dependencies</artifactId>
            <version>2.2.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

注意spring-cloud-openfeign-dependencies寫在spring-cloud-dependencies前面,因為dependency前面的優先生效。

  • 在項目中相同包路徑下新建SentinelContractHolder類,方法實現和spring-cloud-alibaba-sentinel相同,修改Contract接口為新版版本的方法名即可。

總結:

  1. AbstractMethodError是ERROR的子類,不能在編譯時檢查出來,運行時才會觸發

  2. A依賴於B,運行時JVM發現B的class文件和編譯時不一致會拋該異常,一般是因為B有多個版本,版本不兼容導致,比如方法簽名變了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM