以下代码皆为demo示例
背景
在封装Controller基类的过程中,打算把Service对象作为Controller基类泛型的传入,然后在基类统一注入,即实现l类似mybatis-plus其ServiceImpl中的baseMapper属性的效果,这样业务Controller只需要继承该类就可使用其对应的Service对象和一些通用的操作
BaseController类代码如下:
public abstract class BaseController<S> {
@Resource
protected S service;
//一些其他的通用操作
}
问题
我在实现BaseController类后写了一个测试Controller和一个测试的Service对其进行测试,代码如下:
继承BaseController的测试Controller类TestController:
/**
* 测试Controller
*
* @author fgba
* @date 2023/06/09 16:37
*/
@RestController
public class TestController extends BaseController<TestService> {
//增删改查接口
}
对应Service类
/**
* 测试Service
*
* @author fgba
* @date 2023/06/09 16:36
*/
@Service
public class TestService {
//增删改查
}
原本以为很简单,谁知道就在我启动springboot时却报了异常,异常信息如下:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'testController':
Injection of resource dependencies failed;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'java.lang.Object' available: more than one 'primary' bean found among candidates: [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context...
我一看BeanCreationException: Error creating bean with name 'testController'
和org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'java.lang.Object' available: more than one 'primary' bean found among candidates
,这不就是在创建TestController类Bean实例的时候失败,有一个类型为Object的对象bean不是唯一的。可我代码中并没有注入类为Object的bean啊,我TestController类就只注入了一个TestService的对象。
原因
我百思不得其解,细细地查看异常堆栈,找到了异常抛出的地方
at org.springframework.beans.factory.support.DefaultListableBeanFactory.determinePrimaryCandidate(DefaultListableBeanFactory.java:1591) ~[spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
在org.springframework.beans.factory.support.DefaultListableBeanFactory.determinePrimaryCandidate
的1591行抛出的该异常
我首先查看了最有可能有问题的地方,即java.lang.Object类是哪个变量,可以发现requiredType即为异常信息中值为java.lang.Object类的变量,然后再通过异常堆栈信息往上找以及调试,最终发现了requiredType的源头,在CommonAnnotationBeanPostProcessor类的384行,变量field是由反射得来,即在最开始反射属性的时候,其就已经是Object类型,而不是泛型的具体类型TestService,即Java反射无法获取类型为泛型的具体类型
解决方案
查到上面的原因后我马上就疑惑了,那Mybatis-Plus是如何实现的注入泛型对象的呢?
这时发现了一个不同点:Mybatis-Plus使用了@Autowired
注解注入,而我使用了@Resource
注解注入。难道就是因为这个原因?我马上把@Resource
注解换成@Autowired
注解并启动项目,这时确没有出现异常了,项目正常启动了,接口也能正常访问了。