È possibile creare una factory o un proxy che può decidere se il thread è in esecuzione in (Web) Request o background-process (cioè.) e quindi, in base a tali informazioni, crea un bean di sessione o un bean prototipo?Spring: Inject bean dipeso dal contesto (sessione/web o processo thread/background locale)
Esempio (pseudo primavera config :)
<bean id="userInfoSession" scope="session" />
<bean id="userInfoStatic" scope="prototype" />
<bean id="currentUserInfoFactory" />
<bean id="someService" class="...">
<property name="userInfo" ref="currentUserInfoFactory.getCurrentUserInfo()" />
</bean>
Spero che questo rende la mia domanda più facile da capire ...
mia soluzione
Non è mai troppo tardi per aggiornare le proprie domande;). L'ho risolto con due diverse istanze di sessione client, una sessione client SessionScoped e una sessione SingletonScoped. Entrambi sono fagioli normali.
<bean id="sessionScopedClientSession" class="com.company.product.session.SessionScopedClientSession" scope="session">
<aop:scoped-proxy />
</bean>
<bean id="singletonScopedClientSession" class="com.company.product.session.SingletonScopedClientSession" />
<bean id="clientSession" class="com.company.product.session.ClientSession">
<property name="sessionScopedClientSessionBeanName" value="sessionScopedClientSession" />
<property name="singletonScopedClientSessionBeanName" value="singletonScopedClientSession" />
</bean>
Il ClientSession deciderà quindi se singolo o sessione di portata:
private IClientSession getSessionAwareClientData() {
String beanName = (isInSessionContext() ? sessionScopedClientSessionBeanName : singletonScopedClientSessionBeanName);
return (IClientSession) ApplicationContextProvider.getApplicationContext().getBean(beanName);
}
Dove tipo di sessione potrebbero essere raccolte attraverso questo:
private boolean isInSessionContext() {
return RequestContextHolder.getRequestAttributes() != null;
}
Tutte le classi implementano un'interfaccia denominata IClientSession. Sia i bean singletonScoped che sessionScoped si estendono da una BaseClientSession in cui viene trovata l'implementazione.
Ogni servizio quindi possibile utilizzare la sessione client cioè:
@Resource
private ClientSession clientSession;
...
public void doSomething() {
Long orgId = clientSession.getSomethingFromSession();
}
Ora, se andiamo un passo avanti possiamo scrivere qualcosa di simile a un emulatore per la sessione. Questo può essere fatto inizializzando la sessione client (che non è nel contesto di una richiesta) della sessione singleton. Ora tutti i servizi possono utilizzare lo stesso clientSession e siamo ancora in grado di "emulare" un utente cioè:
clientSessionEmulator.startEmulateUser(testUser);
try {
service.doSomething();
} finally {
clientSessionEmulator.stopEmulation();
}
più Un consiglio: si abbia cura di filettatura in caso SingletonScoped clientSession! Wouw, pensavo di poterlo fare con meno linee;) Se ti piace saperne di più su questo approccio non esitare a contattarmi.
Ci proverò. A volte la soluzione più semplice è la migliore e se funziona, perché non è pulito? Alcune altre soluzioni? –
@Frank: il codice che utilizza 'RequestContextHolder' è generalmente difficile da testare. Per questo motivo, dovrebbe essere scoraggiato. – skaffman