2010-04-26 4 views
23

나는 이상한 행동을하고, 내가 Class2의 너무 인터페이스를 구현하는 것을 필요로하는 문제가@Autowire 이상한 문제

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

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

작동 나는 org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type for 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); 
} 

: 난 단지 지금 좋아하는 것 때문에 Class2의 변경했습니다. @Transitional 주석 또는 i mplements IServiceReference<Class3, Long>을 제거하면 문제가 사라지고 bean이 주입되기 때문에 @Transitional 주석이 인터페이스와 호환되지 않는 것으로 보입니다 (비록이 클래스에서 둘 다 가질 필요가 있지만). 주석 대신에 @Transitional이라는 주석을 클래스에 넣으면 발생합니다.

이것이 도움이 될 경우 Spring 3.0.2를 사용합니다.

트랜잭션 방식의 인터페이스와 호환되지 않습니까? 스프링 버그일까요?

답변

28

문제는 클래스 1은 Class2의

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

이 봄 당신은 @Transactional을 표시 클래스에 대한 동적 프록시를 만드는 것입니다 이유의 구체적인 기준을 IServiceReference에 대한 참조를 필요로하지 것입니다. 따라서 Class2가 생성 될 때 Class2 유형은 아니지만 IServiceReference 유형 인 Proxy 객체로 래핑됩니다. 당신이 프록시 지원에 Class2를 사용하는 행위를하려는 경우

당신이 CGLIB 설정해야합니다 아래 읽기 :

스프링스 문서에서 :

스프링 AOP 기본값을 표준 J2SE 동적 프록시를 사용하여 AOP 프록시 용. 이렇게하면 모든 인터페이스 (또는 인터페이스 집합)가 프록시 될 수 있습니다.

스프링 AOP는 CGLIB 프록시를 사용할 수도 있습니다. 인터페이스가 아닌 클래스를 프록시하는 데 필요합니다. 비즈니스 개체가 인터페이스를 구현하지 않으면 CGLIB는 기본적으로 으로 사용됩니다. 클래스가 아닌 인터페이스를 프로그래밍하는 것이 좋습니다. 비즈니스 클래스 은 일반적으로 하나 이상의 비즈니스 인터페이스를 구현합니다. 당신이 필요가 방법에 프록시 개체를 전달할 곳은 당신이 인터페이스에 선언되지 되는 방법, 또는 조언을 을 필요로하는 그 (희망 희귀)의 경우, 힘 CGLIB의 사용 가능 구체적인 유형으로.

봄 AOP가 프록시 기반이라는 사실을 파악하는 것이 중요합니다. 섹션 12.6.1, "AOP 프록시 이해"에 대한 자세한 내용은 정확히 무엇인지 자세히 살펴 보려면 의미 섹션을 참조하십시오.

13

annotation은 주석 처리 된 bean 주위에 프록시 객체를 생성하여 트랜잭션 의미론을 구현하도록 Spring에 지시합니다. 생성 된 프록시는 대상 빈과 동일한 인터페이스를 구현합니다. 따라서 대상 빈이 IServiceReference을 구현하면 생성 된 프록시도 마찬가지입니다.

대상 bean에 구현 된 인터페이스가없는 경우 생성 된 프록시는 대상 bean 유형 인 하위 클래스가됩니다.

Class2에 인터페이스가 구현되어 있지 않으므로 원래 예제에서 트랜잭션 프록시는 Class2의 하위 클래스가됩니다. Class2을 변경하여 IServiceReference을 구현하면 생성 된 프록시가 더 이상 Class2으로 확장되지 않으며 대신 IServiceReference이 구현됩니다. 이로 인해 ClassCastException이 발생했습니다.

이 상황에 가장 적합한 방법은 Class1에서 Class2으로 참조를 제거하고 그 대신 인터페이스를 통해 Class2과 대화하는 것입니다. Class2은 원하는만큼 많은 인터페이스를 구현할 수 있으며, 프록시는 모든 인터페이스를 구현합니다.

스프링이 인터페이스에 관계없이 하위 클래스 프록시를 생성하도록 강요하지만 추가적인 복잡성이 있으므로이를 권장합니다. 또한 this documentation를 참조

+5

기본적으로 내가 말한 것과 똑같은 것입니다. –

1

당신은

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 

를 추가하여 프록시에 강제 할 수 있습니다.

+0

구현 된 인터페이스가 실제로 구성 요소의 배선과 관련이없는 경우 정확히 필요한 것입니다. 매개 변수와 같은 구성 요소를 어딘가에 전달하려고하지만 인터페이스로 입력해야 할 수도 있습니다. 봄과 아무 관련이 없습니다. 인터페이스가 여러 개인 경우 아무런 문제가 없습니다. 단지 하나 있다면 Spring의 일이 그에게 도움이됩니다.이'@ Scope'은 그의 고정을 완벽하게 수정합니다. :-) – virgo47