替换Spring Bean为子类时出现错误

3

我有一个正常工作的调用web服务的功能;我们使用带有注解配置的Spring bean实现调用web服务的逻辑:

@ManagedResource(objectName = "bean:name=XServiceMBean")
@Service("xService")
public class XServiceImpl implements XService
{
// working code here
}

为了测试目的,我想扩展这个类并注入子类代替它,因此我做了以下操作:

@ManagedResource(objectName = "bean:name=XServiceMBean")
@Service("xService")
public class XServiceImplTest extends XServiceImpl
{
// working code here
}

我从超类中注释掉了两行注解。

Spring不喜欢这样做。当我运行时,会出现以下错误:

Error creating bean with name 'xService':Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'xService' must be of type [com.hsc.correspondence.rules.XService], but was actually of type [com.hsc.correspondence.rules.impl.XServiceImplTest]

我尝试了在我的子类上显式添加"implements XService",但结果相同。

在Spring中,我是否做了什么不合法的事情?原始的XServiceImpl中有很多@Resource注释;我认为这不会有影响,我希望它们像以前一样被注入。

有没有办法实现我想要的目标,即使对原始代码进行最小化的更改?(我考虑过在XML中进行配置,但是我不在项目中做出这些决策,但我认为这不会影响我所尝试的内容)。


额外的困惑:错误消息说“名为'xService'的Bean必须是类型...XService,但实际上是XServiceImplTest类型”。但是,XServiceImplTest像XServiceImpl一样实现了XService。

额外的困惑#2:我将整个XServiceImpl复制到类XServiceImplTest中,注释掉了XServiceImpl中的注释,并进行了清理、重建和运行。结果相同。现在这两个类之间唯一的区别就是它们的类名。它变得越来越奇怪。有人能够解释为什么Spring会关心类名吗?


在你的另一个疑惑#2上... 你从XServiceImplTest类中删除了“extends XServiceImpl”吗? - fmodos
是的,但感谢您的确认。 - arcy
2个回答

1
我认为有三种可能的原因:
  1. 您的代码看起来不像您展示的那样,并且继承层次结构不存在。(由于您说您直接添加了接口,这不太可能,但您可能需要仔细检查导入)
  2. 类路径上存在旧的编译类。如果XServiceImplTest的旧编译版本还存在,则可能会被选中。尝试清除所有类/目标文件夹。
  3. 您正在运行某种类加载器问题,并且接口被不同于测试实现的类加载器加载。在抛出异常的行上设置断点并检查涉及各个类的类加载器。

    您可以通过对任何感兴趣的实例执行 x.getClass().getClassLoader() 来执行此操作。在纯香草应用程序中,这将为所有 x 返回相同的实例。在 OSGI 应用程序和 Web 应用程序中,您可能会得到不同的 ClassLoader。ClassLoader 的类型及其父关系应该能够提供一些关于发生情况的提示。


  1. 我使用了 @Override,并在第二个实例中实现了一个接口,该接口只有超类具有方法。
  2. 每次构建之前都要清理一些东西,尽管我以前肯定犯过这样的错误。
  3. 尽管我对Java很有经验,但我不知道在哪里查找“涉及各种类的类加载器”。如果您能指向一个教程,那听起来是我应该知道如何做的事情。我也不认为这是问题所在;它可以很好地处理原始的impl类,并且不太可能被与其包同级别的子类加载器加载。
- arcy

0

它们不能有相同的名称。您正在同时调用“xService”两个类。 您可以为子类提供一个不同的名称,例如“xServiceTest”,并使用@Qualifier注入该名称。 另外,我不是100%确定,但我认为您可能会遇到此类继承问题。如果有问题,只需创建一个具有所有常见实现的抽象类,然后创建2个子类,即服务和测试。

希望这可以帮助您。

[更新]

有人能否建议Spring为什么关心类名?

您可以在配置中检查奇怪的条目。检查是否定义了以下内容:

 <context:component-scan resource-pattern="<path>/*Impl.class" ...> 

以及/或一些特定的包含/排除标准。


该帖子作者声称他从原始类中删除了注解。 - Jens Schauder
就像我说的那样,我注释掉了一组注解,这样每种情况下只有一个类具有“xService”名称。我不知道你所说的“这种继承”,但我不能将功能移动到另一个类中。我也不想为创建测试子类而创建抽象类。 - arcy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接