2014-05-22 3 views
5

Wie kann ich verhindern, dass die @ PostConstruct-Methode für die ProblematischeSerivce von Spring aufgerufen wird, nachdem ich das Objekt zurückgegeben habe?Wie können Spring Life Cycle-Methoden bei der Verwendung von Java Config verhindert werden?

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

Ich glaube, das Ergebnis in einem FactoryBean Verpackung würde die gewünschte Wirkung hat, aber ich brauche diesen Code an mehreren Stellen zu wiederholen, so dass ich für eine elegantere Lösung.

+0

Ich verstehe nicht: Sie haben eine 'Bean @ problematicService(), wo Sie einen' ProblemService' konstruieren, aber Sie sagen, dass es "für mich von anderen Code erstellt". Sie möchten sagen, dass Sie über eine API Zugriff auf 'ProblemService 'haben und Sie müssen es erstellen, aber die API kommt mit einer' @ PostConstruct' Annotation und Sie können das nicht ändern? –

+0

Ja, ProblemematicService kommt mir bereits aus Code außerhalb meiner Kontrolle. –

+0

Werden Sie die annotierte Methode @ PostConstruct aufrufen? Und wird "Problemservice" als "endgültig" deklariert? –

Antwort

4

Dies ist eine nicht-triviale Änderung. Eine @Configuration Klasse (oder besser gesagt die AnnotationConfigApplicationContext) registriert eine CommonAnnotationBeanPostProcessor, die für den Aufruf der -Methode einer Bean zuständig ist. Das würde bedeuten, fast den gesamten Spring IoC Stack zu ändern.

Eigentlich, Sie könnten nur einen CommonAnnotationBeanPostProcessor mit einem Bohnen Namen org.springframework.context.annotation.internalCommonAnnotationProcessor erklären, die man die Standardeinstellung überschreiben wird. Sie können den Init-Annotationstyp auf null setzen, sodass er ignoriert.

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

Vorsichtig bei der Verwendung dieser, wie es andere Dinge brechen könnte.

Ich werde zuerst empfehlen, zu versuchen und einen Weg darum zu finden. Geben Sie beispielsweise ein Wrapper-Objekt zurück, mit dem Sie auf die ProblematicService zugreifen können.

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

Oder ähnlich die FactoryBean Sie vorgeschlagen.

Eine andere, kühlere, aber hässlichere Methode ist das Wrapping des Objekts in einen CGLIB-Proxy.

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

Grundsätzlich kann die init-Methode nie aufgerufen werden.

+0

Schöne CGLib-Lösung, wirklich schlau! +1! Was passiert jedoch, wenn ProblememService ein Transaktionsverhalten aufweist, das Spring dazu zwingt, einen dynamischen JDK-Proxy dafür zu erstellen?Wird die CGLib-Implementierung nicht beschädigt, da CGLib-Proxies nicht in JDK-Proxies erstellt werden können? – geoand

+0

@geoand Guter Punkt. Wir müssten testen, ob CGLIB-Klassen proxisiert werden können. Ich werde brüllen. In der Zwischenzeit habe ich eine sauberere Lösung gegeben. –

+0

Ja, ich habe Ihre aktualisierte Lösung gesehen, und ich muss sagen, ich mag es auch! Ich muss zugeben, dass mir nicht bewusst war, dass die Entscheidung, eine Bean vom Typ Postprozessor zu deklarieren, Spring dazu zwingt, den standardmäßig registrierten zu löschen. Gutes Zeug!!! – geoand

Verwandte Themen