23

自动装配时我有一个奇怪的行为

我有一个类似的代码,它可以工作

@Controller
public class Class1 {
    @Autowired
    private Class2 object2;
    ...
}

@Service
@Transactional
public class Class2{
   ...
}

问题是我需要 Class2 实现一个接口,所以我只更改了 Class2 所以它现在就像:

@Controller
public class Class1 {
    @Autowired
    private Class2 object2;
    ...
}

@Service
@Transactional
public class Class2 implements IServiceReference<Class3, Long>{
   ...
}

public interface IServiceReference<T, PK extends Serializable> {
    public T reference(PK id);
}

使用此代码,我得到一个org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type for Class2. 似乎@Transitional注释与接口不兼容,因为如果我删除@Transitional注释或 implements IServiceReference<Class3, Long>问题消失并且 bean 被注入(尽管我需要在这个类中同时拥有这两者)。如果我将注释@Transitional放在方法而不是类中,也会发生这种情况。

如果有帮助,我会使用 Spring 3.0.2。

接口与事务方法不兼容?它可能是一个春天的错误?

4

3 回答 3

28

问题是您的 Class1 需要对 IServiceReference 的引用,而不是 Class2 的具体引用

@Controller
public class Class1 {
@Autowired
private IServiceReference object2;
    ...
}

这是因为 Spring 正在为您标记为 @Transactional 的类创建动态代理。因此,当创建 Class2 时,它被包装在一个代理对象中,该对象显然不是 Class2 类型,而是 IServiceReference 类型。

如果您想要使用带有代理支持的 Class2 的行为,您必须打开 CGLIB 阅读以下内容:

来自 Springs 文档:

Spring AOP 默认为 AOP 代理使用标准 J2SE 动态代理。这使得任何接口(或一组接口)都可以被代理。

Spring AOP 也可以使用 CGLIB 代理。这是代理类而不是接口所必需的。如果业务对象未实现接口,则默认使用 CGLIB。由于对接口而不是类进行编程是一种很好的做法,因此业务类通常会实现一个或多个业务接口。在那些(希望很少见)需要建议未在接口上声明的方法或需要将代理对象作为具体类型传递给方法的情况下,可以强制使用 CGLIB。

重要的是要掌握 Spring AOP 是基于代理的这一事实。请参阅标题为第 6.6.1 节“了解 AOP 代理”的部分,以彻底检查此实现细节的实际含义。

于 2010-04-26T11:41:26.763 回答
13

注释指示 Spring 围绕带注释的Transactionalbean 生成代理对象,以实现事务语义。生成的代理将实现与目标 bean 相同的接口。因此,如果您的目标 bean 实现IServiceReference了,那么生成的代理也将如此。

如果目标 bean 没有实现的接口,那么生成的代理将改为目标 bean 类型的类。

在您的原始示例中,事务代理将是 的子类Class2,因为Class2未实现任何接口。当您更改Class2为实施IServiceReference时,生成的代理不再扩展Class2,而是实施IServiceReference。这导致您的ClassCastException.

解决这种情况的最佳方法是从 to 中删除引用Class1Class2而是Class2纯粹通过其接口与之对话。Class2可以实现任意数量的接口,代理将实现所有接口。

无论接口如何,您都可以强制 Spring 生成子类代理,但这会带来额外的复杂性,我建议不要这样做。

于 2010-04-26T11:52:23.233 回答
1

您可以通过添加强制它代理

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)

另请参阅此文档

于 2012-07-17T15:22:05.770 回答