apache / dubbo

The java implementation of Apache Dubbo. An RPC and microservice framework.
https://dubbo.apache.org/
Apache License 2.0
40.4k stars 26.42k forks source link

ReferenceAnnotationBeanPostProcessor#isAnnotatedReferenceBean NullPointerException #8104

Closed lucky-xin closed 3 years ago

lucky-xin commented 3 years ago

Environment

 java.lang.NullPointerException: null
    at org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.isAnnotatedReferenceBean(ReferenceAnnotationBeanPostProcessor.java:165) ~[dubbo-3.0.0.jar:3.0.0]
    at org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.postProcessBeanFactory(ReferenceAnnotationBeanPostProcessor.java:131) ~[dubbo-3.0.0.jar:3.0.0]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:325) ~[spring-context-5.3.7.jar:5.3.7]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:191) ~[spring-context-5.3.7.jar:5.3.7]
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746) ~[spring-context-5.3.7.jar:5.3.7]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564) ~[spring-context-5.3.7.jar:5.3.7]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.0.jar:2.5.0]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) [spring-boot-2.5.0.jar:2.5.0]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438) [spring-boot-2.5.0.jar:2.5.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:337) [spring-boot-2.5.0.jar:2.5.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1336) [spring-boot-2.5.0.jar:2.5.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1325) [spring-boot-2.5.0.jar:2.5.0]
![image](https://user-images.githubusercontent.com/13815910/122666643-2e537400-d1e1-11eb-8122-50c9c7831596.png)
ycoe commented 3 years ago

同上

org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#isAnnotatedReferenceBean 165行: annotatedBeanDefinition.getFactoryMethodMetadata() //这个值为null!

只需要有一个被扫描中的接口,没有定义任何方法就会抛这个异常,使用mybatis plus 100%可重现这个错误

liuyunfei1989 commented 3 years ago

最近升级到dubbo3时也遇到了这个问题,如下是我的环境及相关配置: 遗漏了一点忘记提了,在dubbo2.7.12版本下,所有代码都是正常工作的,只在dubbo升级到3时出现了这个问题。

dubbo-spring-boot-starter 3.0.0 mybatis-spring-boot-starter 2.2.0 spring-cloud-starter 2.3.12.RELEASE JDK 11

经过调试后,发现在同时使用mybatis的@MapperScan与dubbo的@DubboComponentScan的情况下,会导致程序运行到下面的地方,即 getFactoryMethodMetadata():

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.lang.Nullable; import org.springframework.util.Assert;

/**

}

而这里是被 org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor所调用的,调用处的代码段在162行,如下:

private boolean isAnnotatedReferenceBean(BeanDefinition beanDefinition) { if (beanDefinition instanceof AnnotatedBeanDefinition) { AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition; String beanClassName = annotatedBeanDefinition.getFactoryMethodMetadata().getReturnTypeName(); if (ReferenceBean.class.getName().equals(beanClassName)) { return true; } } return false; }

ScannedGenericBeanDefinition继承自AnnotatedBeanDefinition,但在spring的源代码中,这里是返回null的,但是关于这个类的介绍是这样的:

Extension of the GenericBeanDefinition class, based on an ASM ClassReader, with support for annotation metadata exposed through the AnnotatedBeanDefinition interface. This class does not load the bean Class early. It rather retrieves all relevant metadata from the ".class" file itself, parsed with the ASM ClassReader. It is functionally equivalent to AnnotatedGenericBeanDefinition.AnnotatedGenericBeanDefinition(AnnotationMetadata) but distinguishes by type beans that have been scanned vs those that have been otherwise registered or detected by other means. Since: 2.5 See Also: getMetadata(), getBeanClassName(), org.springframework.core.type.classreading.MetadataReaderFactory, AnnotatedGenericBeanDefinition Author: Juergen Hoeller, Chris Beams

这里提到和ASM有关,所以我怀疑这里有可能实际上被调用的是一个增强后的方法,但我目前还不确定。

这个问题发生的很奇怪,当你使用mybatis的@MapperScan与dubbo的@DubboComponentScan其中之一的时候,是不会出现这个问题的,所以我不清楚是不是我在这两个组件的集成过程中是不是使用了不恰当的方式。

我目前在这个问题上花费的时间在5小时左右,因为我现在的工作比较忙,回家的话需要带娃,所以还没有抽出更多的时间去排查。如果可以,我希望能在这里更快地得到一些指点,如果从这里找不到答案的话,我会在后面专门抽出时间去排查一下这个问题。

另外,我不确定是不是我集成的其他组件或代码,例如其他组件的bean注册或是SPI等机制导致了这个问题,我在下面贴出可能涉及此问题的代码: 其中可能相关的组件包括

spring-boot-starter 2.3.12.RELEASE spring-boot-starter-webflux 2.3.12.RELEASE mybatis-spring-boot-starter 2.2.0 dubbo-spring-boot-starter 3.0.0 sharding-jdbc-spring-boot-starter 4.1.1 seata-spring-boot-starter 1.4.2 spring-cloud Hoxton.SR11 pulsar-client 2.8.0

以下是相关的配置代码:

dubbo相关配置: package com.blue.finance.config.universal;

import com.blue.finance.config.deploy.DubboDeploy; import org.apache.dubbo.config.*; import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;

import static com.blue.dubbo.api.FilterBeanName.BLUE_EXCEPTION_FILTER;

/**

}

数据访问相关配置: package com.blue.finance.config.universal;

import com.blue.identity.api.IdentityConf; import com.blue.base.common.pro.MathProcessor; import com.blue.base.constant.common.Symbol; import com.blue.sharding.core.DatabaseShardingAlgorithm; import com.blue.sharding.core.TableShardingAlgorithm; import com.blue.sharding.model.ShardYmlAttr; import com.blue.seata.model.UndoYmlAttr; import com.blue.finance.config.deploy.DataDeploy; import com.blue.finance.config.deploy.IdentityDeploy; import com.zaxxer.hikari.HikariDataSource; import io.seata.rm.datasource.DataSourceProxy; import org.apache.ibatis.logging.stdout.StdOutImpl; import org.apache.ibatis.session.AutoMappingBehavior; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration; import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration; import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration; import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.MapperScan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; import java.util.stream.LongStream;

import static java.util.Optional.of; import static java.util.Optional.ofNullable;

/**

}

最后,谢谢作者及所有的维护人员及帮助dubbo更好发展的人们。

lucky-xin commented 3 years ago

Spring在org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#postProcessBeanFactory方法中扫描所有IoC中的BeanDefinition,如果BeanDefinition为ScannedGenericBeanDefinition则都会空指针(代码没有很严谨) image 我看了3.0.1-SNAPSHOT里面已经修复了

hozhis commented 3 years ago

dubbo 3.0 和 mybatis 2.2.0 一起使用就会报错,dubbo单独使用OK image image

kylixs commented 3 years ago

This error has bean fixed: https://github.com/apache/dubbo/pull/8080 We will release version 3.0.1 recently to solve this problem.