@Autowire奇怪的问题
自动assembly时我有一种奇怪的行为
我有类似这样的代码,它的工作原理
@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{ ... } public interface IServiceReference { public T reference(PK id); }
使用此代码,我得到一个org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type for Class2
。 似乎@Transitional
注释与接口不兼容,因为如果我删除@Transitional
注释或者mplements IServiceReference
问题消失并注入bean(尽管我需要在这个类中都有)。 如果我将注释@Transitional
放在方法而不是类中,也会发生这种情况。
如果这有帮助,我使用Spring 3.0.2。
与事务方法的接口不兼容? 可能是spring的bug吗?
问题是你的Class1需要引用IServiceReference而不是Class2的具体引用
@Controller public class Class1 { @Autowired private IServiceReference object2; ... }
这是因为Spring正在为您标记为@Transactional的类创建动态代理。 因此,当创建Class2时,它包装在一个Proxy对象中,该对象显然不是Class2类型,但是类型为IServiceReference。
如果您希望使用具有代理支持的Class2的行为,则必须打开以下CGLIB:
来自Springs Doc:
Spring AOP默认使用AOP代理的标准J2SE动态代理。 这使得任何接口(或接口集)都可以被代理。
Spring AOP也可以使用CGLIB代理。 这是代理类而不是接口所必需的。 如果业务对象未实现接口,则默认使用CGLIB。 由于优化的做法是编程接口而不是类,业务类通常会实现一个或多个业务接口。 可以强制使用CGLIB,在那些需要建议未在接口上声明的方法或需要将代理对象作为具体类型传递给方法的情况下(希望很少见)。
掌握Spring AOP是基于代理的这一事实非常重要。 请参阅第6.6.1节“了解AOP代理”一节,以全面了解此实现细节的实际含义。
Transactional
注释指示Spring围绕带注释的bean生成代理对象,以实现事务语义。 生成的代理将实现与目标bean相同的接口。 因此,如果您的目标bean实现了IServiceReference
,那么生成的代理也是如此。
如果目标bean没有实现的接口,那么生成的代理将成为目标bean类型的子类。
在您的原始示例中,事务代理将是Class2
的子类,因为Class2
没有实现接口。 当您更改Class2
以实现IServiceReference
,生成的代理不再扩展Class2
,而是实现IServiceReference
。 这导致了ClassCastException
。
解决这种情况的最佳方法是从Class1
删除引用到Class2
,而不是纯粹通过它的接口与Class2
对话。 Class2
可以实现任意数量的接口,代理将实现所有接口。
无论接口如何,您都可以强制Spring生成子类代理,但这是额外的复杂性,我建议不要使用它。
您可以通过添加强制它代理
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
另见本文档 。