2011-03-07 8 views
2

응용 프로그램 컨텍스트에서 Bean을 추출하려고합니다.응용 프로그램 컨텍스트 bean

그래서 클래스 정의 :

public class ApplicationContextProvider implements ApplicationContextAware { 

    private static ApplicationContext applicationContext; 

    public static ApplicationContext getApplicationContext() { 
     return applicationContext; 
    } 
    public void setApplicationContext(ApplicationContext _applicationContext) throws BeansException { 
     applicationContext = _applicationContext; 

    } 

} 

내 applicationContext.xml에 내 코드에서 그러나

<bean id="workflowService" class="com.mycompany.util.WorkflowService"> 
    <bean id="applicationContextProvider" class="com.mycompany.util.ApplicationContextProvider"></bean> 
    <context:annotation-config /> 

내가하려고하면

WorkflowService service = (WorkflowService) ApplicationContextProvider.getApplicationContext().getBean("workflowService"); 

내가 얻을 :

java.lang.ClassCastException가 : $ Proxy40이 com.mycompany.util.WorkflowService

캐스트 할 수없는 편집 :

WorkflowService 코드 : 나는 WorkflowService를 추측

public class WorkflowService implements Serializable { 
    ... 
    @PostConstruct 
     public void init() { 
    } 
    ... 
    @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) 
     public Collection<lData> findData(Integer contractId) { 
    }  
} 
+0

이 하나의 상대 - http://stackoverflow.com/questions/5133291/applicationcontextprovider-is-not-being-called - 나는 당신이 인터페이스 V까지 혼합하고 추측 할 구체적인 클래스를 여러분의 빈에. 정의/참조. WorkflowService 코드를 게시하십시오. –

답변

3

가있다 적어도 하나의 인터페이스를 구현하는 클래스 (충분한 코드를 제공하지 않았다). Spring에서 정확한 클래스를 검색하려고 시도하는 동안 인터페이스 중 하나를 요청해야합니다.

이는 대부분의 경우 스프링이 여러 프록시 (예 : 트랜잭션 프록시)에 빈을 래핑하기 때문입니다. 클래스가 적어도 하나의 인터페이스를 구현하면 결과 프록시는 모든 인터페이스를 구현하지만 원래 클래스로 캐스트 할 수 없습니다. 클래스가 어떤 인터페이스도 구현하지 않는다면 (보통 헤비급 서비스의 경우 나쁜 것으로 생각되지만), Spring은 원래 클래스의 CGLIB 서브 클래 싱을 사용합니다. 이 경우 코드가 유효합니다.

+0

올바른 영역에있는 것 같지만 오류 해결을위한 간단한 해결책이있을 것입니다. 는 WorkflowService에 대한 주석을 제안합니다. 여러분이 말하는 것처럼 프록시 될 것입니다. @Odelya - 사용중인 WorkflowService 및 특수 효과 코드를 게시하십시오. 하나는 @Service를 추측 할 수 있습니까? –

+0

또한 : 애플 리케이션 컨텍스트 내에서 xml - 안쪽 bean 인 applicationContextProvider가 아님 - 외부 bean을 "볼 수 있습니까?" –

+0

@David, Tomasz - workflowservice 코드로 내 질문을 편집했습니다. – Dejell

4

귀하의 문제는이 비트입니다 :

WorkflowService implements Serializable 

봄이 클래스가하는 모든 인터페이스 구현됩니다 생성하는 모든 프록시 - 거의 확실하게 당신이 원하지 않는 것입니다이 경우, Serializable에 있습니다.

메서드가 포함 된 WorkflowService에서 새 인터페이스를 추출해야합니다 (WorkflowOperations이라고 부름). 인터페이스를 구현하면 해당 인터페이스로 전송할 수 있습니다 (예 :

public interface WorkflowOperations { 
    Collection<lData> findData(Integer contractId); 
} 


public class WorkflowService implements WorkflowOperations { 

    ... 
    @PostConstruct 
     public void init() { 
    } 
    ... 
    @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) 
     public Collection<lData> findData(Integer contractId) { 
    } 

} 

다음 :

WorkflowOperations service = (WorkflowOperations) ApplicationContextProvider.getApplicationContext().getBean("workflowService"); 

당신은 아마 또한 WorkflowService에서 Serializable을 제거해야합니다. 거의 확실하게 이것을 필요로하지 않는다. 스프링 빈을 직렬화하는 것은 이치에 맞지 않는다. 버릇없이 방금 Serializable을 추가했다면 제거하고 (그 습관을 벗어나십시오).

+0

+1. 예 - 당신이 그것을 절실히 필요로하지 않는 한 Serializable을 피하십시오. Bloch 'Effective Java'읽기 - v. Serializable의 단점에 대한 철저한 논의. –

2

서비스에 @Transactional이라는 주석을 달았 기 때문에 Spring Bean과 동일한 인터페이스를 구현하지만, WorkflowService이 아닌 트랜잭션 JDK 동적 프록시가 서비스 bean을 래핑합니다. 따라서 변수 WorkflowService에 할당하려고하면 ClassCastException이 표시됩니다.

  • 귀하의 비즈니스 방법과 인터페이스 WorkflowService를 지정하고 WorkflowServiceImpl 클래스를 구현 : 나는 두 가지 솔루션을 참조하십시오. 그런 다음 Spring 컨텍스트에서 bean 정의를 WorkflowService에서 WorkflowServiceImpl으로 변경하십시오. 이것은 제가 권장하는 것입니다, 일반적인 디자인 원칙과 특별히 Spring 환경에서 작업하는 것입니다 : Spring은 인터페이스를 좋아합니다.

  • 스프링 컨텍스트에서 <tx:annotation-driven/> 요소에 proxy-target-class="true"을 추가하면 하위 클래스로 프록시를 구현하도록 스프링이 지정되어 proxy instanceof WorkFlowService이 true가됩니다. 나는이 해결책이 더러운 것을 안다. 또한 CGLIB에 이런 방식으로 의존성을 추가하는 것에주의하십시오.

관련 문제