2015-02-05 13 views
5

nicht auf den im Frühjahr Rahmen commit Zusammenhang https://github.com/spring-projects/spring-framework/commit/5aefcc802ef05abc51bbfbeb4a78b3032ff9eee3Feder Cache @Cacheable während @PostConstruct Verwendung funktioniert

die Initialisierung von afterPropertiesSet zu einem späteren Zeitpunkt gesetzt() zu afterSingletonsInstantiated()

In Kürze: Dies verhindert, dass das Caching funktioniert, wenn es in einem @ PostConstruct-Anwendungsfall verwendet wird.

Längere Version: Dies verhindert die Verwendung Fall, in dem Sie sich

  1. erstellen serviceB mit @Cacheable auf einem methodeB

  2. erstellen serviceA mit @PostConstruct Aufruf serviceB.methodB

    @Component 
    public class ServiceA{ 
    
    @Autowired 
    private ServiceB serviceB; 
    
    @PostConstruct 
    public void init() { 
        List<String> list = serviceB.loadSomething(); 
    } 
    

Dies führt dazu, dass org.springframework.cache.interceptor.CacheAspectSupport jetzt nicht initialisiert wird und das Ergebnis nicht zwischengespeichert wird.

protected Object execute(CacheOperationInvoker invoker, Object target, Method method, Object[] args) { 
    // check whether aspect is enabled 
    // to cope with cases where the AJ is pulled in automatically 
    if (this.initialized) { 
//>>>>>>>>>>>> NOT Being called 
     Class<?> targetClass = getTargetClass(target); 
     Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass); 
     if (!CollectionUtils.isEmpty(operations)) { 
     return execute(invoker, new CacheOperationContexts(operations, method, args, target, targetClass)); 
     } 
    } 
//>>>>>>>>>>>> Being called 
    return invoker.invoke(); 
} 

Meine Abhilfe ist, manuell die Initialisierung Methode aufzurufen:

@Configuration 
public class SomeConfigClass{ 

    @Inject 
    private CacheInterceptor cacheInterceptor; 

    @PostConstruct 
    public void init() { 
    cacheInterceptor.afterSingletonsInstantiated(); 
    } 

Das ist natürlich mein Problem behebt, aber hat es Nebenwirkungen andere, die nur 2-mal aufgerufen wird (1 Handbuch und 1 durch die Rahmen wie beabsichtigt)

Meine Frage lautet: „ist dies eine sichere Abhilfe als der anfängliche commiter zu tun schien ein Problem zu haben, wo nur die afterPropertiesSet() mit“

+0

Die '@ PostConstruct' keine Garantie gibt, dass Proxies sind bereits angelegt (das ist der gleiche Grund, warum' @ Transactional' funktioniert nicht für '@ PostConstruct' Methoden.Die @ PostConstruct-Methode wird direkt nach der Konstruktion und nach der Injektion der Abhängigkeiten aufgerufen, aber fast immer vor dem Punkt, an dem Proxies erzeugt wurden. Warum brauchst du es in einer @ PostConstruct-Methode? Im Allgemeinen ist ein 'ApplicationListener ' besser als das Implementieren der 'SmartInitializingSingleton'-Schnittstelle anstelle von' @ PostConstruct '. –

+0

Vielen Dank für Ihre Antwort. Wir verwenden das postconstruct, um eine Bean mit Werten zu initialisieren, die von einem anderen Service genommen wurden (der @Cacheable auf seinen Methoden hat). Wir erwarteten, dass diese Werte auch dann zwischengespeichert würden, wenn ein Postconstruct verwendet würde. Wenn dies nicht der Fall ist, würde ein Java-Dokument das Framework unterstützen, da andere Entwickler dies möglicherweise ebenfalls nicht wissen. Werde den SmartInitializingSingleton stattdessen versuchen. Vielen Dank! – user2966436

+0

Dies wird in [dem Referenzhandbuch] erklärt (http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-lifecycle-default-init-destroy-methods) lies den letzten Abschnitt dieses Abschnitts. –

Antwort

3

Wie Marten bereits gesagt hat, dürfen Sie keinen dieser Dienste in der PostConstruct-Phase verwenden, da Sie nicht garantieren können, dass der Proxy-Interceptor zu diesem Zeitpunkt vollständig gestartet wurde.

Am besten laden Sie Ihren Cache, indem Sie auf ContextRefreshedEvent (mehr Unterstützung für 4.2) warten und die Arbeit dort erledigen. Davon abgesehen, verstehe ich, dass es nicht klar sein kann, dass eine solche Verwendung verboten ist, also habe ich SPR-12700 erstellt, um die Dokumentation zu verbessern. Ich bin mir nicht sicher, auf welches Javadoc du dich beziehst.

Um Ihre Frage zu beantworten: Nein, es ist keine sichere Lösung. Was du zuvor benutzt hast, arbeitete mit "Nebeneffekt" (d. H. Es sollte nicht funktionieren, wenn dein Bean vor dem CacheInterceptor initialisiert wurde, hättest du das gleiche Problem mit einer älteren Version des Frameworks). Rufen Sie solche Low-Level-Infrastruktur nicht in Ihrem eigenen Code auf.

2

hatte genau das gleiche Problem wie OP und hören ContextRefreshedEvent wurde verursacht, meine Initialisierung Methode zweimal aufgerufen werden. Das Hören von ApplicationReadyEvent funktionierte am besten für mich. Hier ist der Code I

verwendet
@Component 
public class MyInitializer implements ApplicationListener<ApplicationReadyEvent> { 
    @Override 
    public void onApplicationEvent(ApplicationReadyEvent event) { 
     //doing things 
    } 
} 
Verwandte Themen