2014-05-22 1 views
5

개체를 반환 한 후에 Spring에서 ProblematicSerivce의 @PostConstruct 메서드를 호출하지 못하게하려면 어떻게해야합니까?Java 구성을 사용할 때 스프링 수명주기 방법을 방지 할 수있는 방법은 무엇입니까?

@Configuration 
class MyConfig { 
    @Bean 
    public ProblematicService problematicService() { 
     ProblematicService service = someMethodOutsideMyControl(); 
     // ProblematicService is constructed for me by other code (outside of Spring) 
     // and it happens to have a @PostConstruct method. The @PostConstruct method 
     // cannot be invoked here or by Spring once this method returns. 
     return service; 
    } 
} 

내가 원하는 효과를 가질 것의 FactoryBean에 결과를 감싸는 생각하지만, 나는 여러 장소에서이 코드를 반복해야합니다, 그래서 더 우아한 해결책을 찾고 있어요.

+0

당신이'ProblematicService'를 생성하는 곳에'@ Bean' problematicService()가 있습니다 만, "다른 코드에 의해 생성되었습니다"라고 당신은 말할 수 있습니다. 당신은 API로부터'ProblematicService'에 접근 할 수 있고 그것을 빌드해야한다고 말하고 싶지만, API는'@ PostConstruct' 주석을 가지고 있습니다. 당신은 그것을 변경할 수 없습니까? –

+0

예, ProblematicService는 이미 내 컨트롤 외부의 코드에서 생성되었습니다. –

+0

당신은 모두'@ PostConstruct' 주석 메소드를 호출 할 것입니까? 'ProblematicService'는'final'으로 선언되어 있습니까? –

답변

4

이것은 별다른 변경 사항이 아닙니다. @Configuration 클래스 (또는 AnnotationConfigApplicationContext)는 @PostConstruct 빈을 호출하는 역할을 담당하는 CommonAnnotationBeanPostProcessor을 등록합니다. 변경은 거의 모든 Spring IoC 스택을 변경한다는 것을 의미합니다.

실제로 인 경우 이라는 기본값으로 덮어 쓰는 으로 CommonAnnotationBeanPostProcessor을 선언하면됩니다. init 애노테이션 유형을 null으로 설정하여 @PostConstruct을 무시할 수 있습니다.

@Bean(name = "org.springframework.context.annotation.internalCommonAnnotationProcessor") 
public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() { 
    CommonAnnotationBeanPostProcessor bean = new CommonAnnotationBeanPostProcessor(); 
    bean.setInitAnnotationType(null);; 
    return bean; 
} 

다른 것들을 손상시킬 수 있으므로 사용하는 동안 조심하십시오.

나는 먼저 그 방법을 찾으려고 노력할 것을 권합니다. 예를 들어 ProblematicService에 액세스 할 수있는 래퍼 객체를 반환합니다.

@Bean 
public ServiceProvider provider() { 
    ProblematicService service = ...; 
    ServiceProvider provider = new ServiceProvider(service); 
    return provider; 
} 

또는 마찬가지로 FactoryBean을 제안했습니다.

CGLIB 프록시로 객체를 래핑하는 것이 더 시원하고 추악한 방법입니다.

@Bean 
public ProblematicService service() { 
    ProblematicService service = ...; 
    Enhancer enhancer = new Enhancer(); 
    enhancer.setSuperclass(service.getClass()); 
    enhancer.setCallback(new MethodInterceptor() { 
     ProblematicService inner = service; 
     @Override 
     public Object intercept(Object obj, Method method, Object[] args, 
        MethodProxy proxy) throws Throwable { 
      if (!method.getName().equals("initMethodName")) 
       return method.invoke(inner, args); 
      return null; 
     } 
    }); 
    return (ProblematicService) enhancer.create(); 
} 

기본적으로 init 메소드를 호출 할 수 없습니다.

+0

정말 멋진 CGLib 솔루션! +1! 그러나 ProblematicService가 JDK 동적 프록시를 생성하도록 Spring을 강제하는 일부 트랜잭션 동작이있는 경우에는 어떻게됩니까?JDK 프록시에서 CGLib 프록시를 만들 수 없으므로 CGLib 구현을 중단하지 않겠습니까? – geoand

+0

@geoand 좋은 지적. CGLIB 클래스가 프록시 될 수 있는지 테스트해야합니다. 내가 갈거야. 그동안 나는 더 깨끗한 해결책을 제시했습니다. –

+0

예 당신의 업데이트 된 솔루션을 보았습니다. 나는 그것을 좋아한다고 말해야합니다! 포스트 프로세서 타입의 빈을 선언하면 스프링이 기본 등록 된 것을 버리도록 강요한다는 사실을 나는 인식하지 못했다. 좋은 물건! !! – geoand