2016-05-31 27 views
5

Ho provato un sacco di cose ora ma mi sembra di perdere un pezzo del puzzle. Ecco la storia: ho un bean con scope richiesta che legge SessionContext da HttpServletRequest. Questo attributo è impostato in un filtro. Quindi funziona perfettamente mentre il codice gira sul thread corretto.Spring promosso bean con scope di richiesta ai thread figlio (HttpServletRequest)

@Component 
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES) 
public class SessionContextProviderImpl implements SessionContextProvider<SessionContext> { 
    private final HttpServletRequest _request; 

    @Autowired 
    public SessionContextProviderImpl(HttpServletRequest request) { 
     _request = request; 
    } 

    @Override 
    public SessionContext get() { 
     return (SessionContext) _request.getAttribute(Constants.SESSION_CONTEXT_IDENTIFIER); 
    } 
} 

Ora ho iniziato ad usare 8s java nuova funzionalità CompletableFuture e ho tre di quelle caratteristiche di calcolo roba in parallelo, mentre le attese richiesta di filo per il risultato. Quello che voglio fare è promuovere/consegnare/propagare il bean o la richiesta in modo che possa essere usato sui thread figli che sono stati generati dal thread http originale. In particolare, vorrei ottenere SessionContext da HttpServletRequest da un CompletableFuture fornito asincrono.

quello che è provato questo (sostituito implementazione di get):

final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 
request.getAttribute(Constants.SESSION_CONTEXT_IDENTIFIER); 

Ma questo ha ovviamente lo stesso risultato della richiesta ambito fagiolo. Bene "getRequest" restituisce null invece di un'eccezione generata.

Come terzo approccio ho provato questo original post:

ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory; 

org.springframework.beans.factory.config.Scope simpleThreadScope = new SimpleThreadScope(); 

cbf.registerScope("simpleThreadScope", simpleThreadScope); 

E i Impostare la portata del SessionContextProviderImpl essere "simpleThreadScope". Sfortunatamente, questo non ha funzionato e ha generato un'eccezione che viene utilizzata al di fuori dell'ambito di una richiesta.

L'ambiente che sto utilizzando: Jersey con iniezione a molla.

Forse qualcuno ha qualche idea?

riguarda

risposta

6

Per eventuali futuri avventurieri:

ho preso un po 'di tempo per scavare attraverso il codice primavera e ha scoperto che ha un RequestContextHolder inheritableRequestAttributesHolder. Se si esamina la documentazione di ciò che è (ereditando da: InheritableThreadLocal) si legge quanto segue:

Le variabili locali filettabili ereditabili vengono utilizzate preferibilmente rispetto alle normali variabili locali del thread quando l'attributo per-thread viene mantenuto nella variabile (ad esempio, ID utente, ID transazione) deve essere automaticamente trasmesso a qualsiasi thread figlio creato.

Quindi il RequestContextHolder ha un campo per quello e in realtà setRequestAttributes supporta un flag per utilizzare inheritableRequestAttributesHolder. Inoltre se si guarda a RequestContextListener -> requestInitialized si trova che viene chiamato senza il flag (= false). Così che cosa ho finito per fare è questa:

public class InheritableRequestContextListener extends RequestContextListener { 
    private static final String REQUEST_ATTRIBUTES_ATTRIBUTE = 
     InheritableRequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES"; 

    @Override 
    public void requestInitialized(ServletRequestEvent requestEvent) { 
     if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) { 
      throw new IllegalArgumentException(
        "Request is not an HttpServletRequest: " + requestEvent.getServletRequest()); 
     } 
     HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest(); 
     ServletRequestAttributes attributes = new ServletRequestAttributes(request); 
     request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes); 
     LocaleContextHolder.setLocale(request.getLocale()); 
     RequestContextHolder.setRequestAttributes(attributes, true); 
    } 
} 

E voilà, posso accedere SessionContextProvider nel thread figlio.

+0

Come si utilizzano gli attributi di richiesta dopo che la richiesta è stata completata. Sto perdendo gli attributi della mia richiesta come gli attributi delle intestazioni una volta che la richiesta è stata completata. Ho provato a usare RequestContextHolder.setRequestAttributes (attributes, true); ancora senza fortuna. –

+0

Se si desidera utilizzare il contesto su una discussione che non bock l'esecuzione della richiesta e quindi agire in modo completamente indipendente, è necessario cercare soluzioni diverse come questa: DelegatingSecurityContextExecutor https: // docs.spring.io/spring-security/site/docs/current/reference/html/concurrency.html –

+0

È un componente? Una classe di configurazione? Quale annotazione devo inserire sulla classe? –

Problemi correlati