@Autowire奇怪的问题

2022-09-01 22:50:32

我在自动布线时有一个奇怪的行为

我有一个类似的代码,它的工作原理

@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);
}

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

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

接口是否与事务方法不兼容?可能是春天的虫子吗?


答案 1

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

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

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

如果您希望将Class2与代理支持一起使用,则必须在下面打开CGRIB Read:

从斯普林斯文档:

Spring AOP 默认对 AOP 代理使用标准 J2SE 动态代理。这样就可以代理任何接口(或一组接口)。

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

重要的是要掌握Spring AOP是基于代理的事实。请参见第 6.6.1 节 “了解 AOP 代理”一节,全面了解此实现细节的确切含义。


答案 2

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

如果目标 Bean 没有实现的接口,则生成的代理将改为目标 Bean 类型的子类

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

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

你可以强制Spring生成子类代理,而不管接口如何,但这是额外的复杂性,我建议不要这样做。


推荐