복붙노트

[SPRING] @Autowire 이상한 문제

SPRING

@Autowire 이상한 문제

autowiring 할 때 나는 이상한 행동을한다.

이 코드와 비슷한 코드가 있는데 작동합니다.

@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을 얻는다 : Class2를위한 타입의 일치하는 bean이 없다. @Transitional 주석을 제거하거나 IServiceReference 을 구현하면 문제가 사라지고 bean이 주입되기 때문에 @Transitional 주석은 인터페이스와 호환되지 않는 것으로 보입니다 (비록이 클래스에서 둘 다 가질 필요가 있지만). @Transitional 주석을 클래스 대신에 메서드에 넣으면 발생합니다.

이것이 도움이된다면 Spring 3.0.2를 사용한다.

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

해결법

  1. ==============================

    1.문제는 Class1이 IServiceReference에 대한 참조가 필요하며 Class2의 구체적인 참조가 필요하지 않다는 것입니다.

    문제는 Class1이 IServiceReference에 대한 참조가 필요하며 Class2의 구체적인 참조가 필요하지 않다는 것입니다.

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

    그 이유는 Spring이 @Transactional이라고 표시된 클래스에 대한 동적 프록시를 생성하기 때문입니다. 따라서 Class2가 생성 될 때 Class2 유형은 아니지만 IServiceReference 유형 인 Proxy 객체로 래핑됩니다.

    프록시 지원으로 Class2를 사용하는 동작을 원할 경우 CGLIB를 켜야합니다 아래를 읽으십시오 :

    스프링 박사님 :

  2. ==============================

    2.Transactional annotation은 트랜잭션 semantics를 구현하기 위해 Annotated Bean 주위에 프록시 객체를 생성하도록 Spring에 지시합니다. 생성 된 프록시는 대상 bean과 동일한 인터페이스를 구현합니다. 따라서 대상 빈에서 IServiceReference를 구현하면 생성 된 프록시도 함께 구현됩니다.

    Transactional annotation은 트랜잭션 semantics를 구현하기 위해 Annotated Bean 주위에 프록시 객체를 생성하도록 Spring에 지시합니다. 생성 된 프록시는 대상 bean과 동일한 인터페이스를 구현합니다. 따라서 대상 빈에서 IServiceReference를 구현하면 생성 된 프록시도 함께 구현됩니다.

    타겟 빈에 구현 된 인터페이스가 없다면, 생성 된 프록시는 대신 타겟 빈 타입의 서브 클래스가 될 것이다.

    원래 예제에서 Class2는 인터페이스를 구현하지 않았기 때문에 트랜잭션 프록시는 Class2의 하위 클래스가됩니다. IServiceReference를 구현하도록 Class2를 변경하면 생성 된 프록시가 더 이상 Class2를 확장하지 않고 대신 IServiceReference를 구현합니다. 이로 인해 ClassCastException이 발생했습니다.

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

    Spring이 인터페이스에 상관없이 Spring에게 하위 클래스 프록시를 생성하도록 강요 할 수 있지만 추가적인 복잡성이 있습니다.

  3. ==============================

    3.추가하여 강제로 프록시로 설정할 수 있습니다.

    추가하여 강제로 프록시로 설정할 수 있습니다.

    @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
    

    또한이 문서를 참조하십시오.

  4. from https://stackoverflow.com/questions/2713033/autowire-strange-problem by cc-by-sa and MIT license