web-dev-qa-db-fra.com

Java/Spring MVC: fournit un contexte de requête aux threads enfants

J'ai le problème, que je veux externaliser certains processus de mon application Spring WebMVC dans des threads séparés. C'était assez facile et ça marche, jusqu'à ce que je veuille utiliser une classe, userRightService, qui utilise la requête globale. Ce n'est pas disponible dans les discussions, et nous avons un problème, c'est assez compréhensible.

C'est mon erreur:

Java.lang.RuntimeException:
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'scopedTarget.userRightsService': Scope 'request' is not active
for the current thread; consider defining a scoped proxy for this bean if
you intend to refer to it from a singleton; nested exception is 
Java.lang.IllegalStateException: Cannot ask for request attribute - 
request is not active anymore!

Ok, assez clair. J'essaie de conserver le contexte de la demande en implémentant cette solution: 

Comment activer la portée de la demande dans l'exécuteur de tâche asynchrone

Ceci est ma classe exécutable:

@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class myThread implements Runnable {

  private RequestAttributes context;

  public DataExportThread(RequestAttributes context) {
    this.context = context;
  }

  public void run() {
    RequestContextHolder.setRequestAttributes(context);

Et c'est là que ça se produit:

final DataExportThread dataExportThread = 
   new myThread(RequestContextHolder.currentRequestAttributes());

final Thread thread = new Thread(myThread);
thread.setUncaughtExceptionHandler((t, e) -> {...});
thread.start();

Autant que je sache, nous stockons les currentRequestAttributes dans le fil puis, lorsque nous les exécutons, nous les restaurons currentRequestAttributes ... me semblait solide, mais l'erreur est toujours là. Je pense avoir commis une erreur en adaptant la solution à mon cas. peut-être que quelqu'un peut m'aider à trouver l'erreur.

Avant de passer en revue beaucoup de threads stackoverflow avec différentes solutions (voir ci-dessous), je pouvais donc essayer autre chose, mais celle-ci me semblait la plus claire et la plus simple. J'espère donc que quelqu'un pourra m'aider à trouver l'erreur dans la mise en œuvre. ou expliquer pourquoi c'est la mauvaise approche.

J'ai déjà essayé celui-ci sans succès:

Si c'est important:

<org.springframework-version>4.3.4.RELEASE</org.springframework-version>

BTW: Je sais qu'il serait préférable de restructurer l'application de manière à ce que la requête ne soit pas nécessaire dans le thread, mais c'est très compliqué dans ce cas et j'espère vraiment que je pourrai l'éviter.

-

Edit1:

Le Bean qui ne peut pas être créé dans le fil commence comme ceci:

@Service("userRightsService")
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserRightsService {

-

Edit2:

J'ai aussi essayé celui-ci:

Mais le contexte est toujours vide ...

8
Paflow

Pour ceux qui cherchent. Avec l'aide des astuces de Master_Ex, j'ai trouvé une solution:

Dans le runnable:

private HttpServletRequest request;

public void run() {

    final RequestContextListener rcl = new RequestContextListener();
    final ServletContext sc = request.getServletContext();
    rcl.requestInitialized(new ServletRequestEvent(sc, request));

Et dans UserRightService, j'appelle une fonction qui effectue les opérations suivantes:

    SecurityContext context = SecurityContextHolder.getContext();
    Authentication auth = context.getAuthentication();

    context.setAuthentication(getDataExportAuthentication(exportingUser));

@ Master_Ex's Thank You, votre message a été très utile. Je suis tellement désolé que je sois trop tard pour vous donner la prime, sinon je l'aurais marquée comme étant la bonne.

0
Paflow

Je ne peux pas reproduire le problème car je ne sais pas comment vous créez/injectez la UserRightsService mais j'ai quelques suggestions que vous pouvez essayer.

Je suppose que le problème est que la variable RequestAttributes est invalidée car la demande est terminée (c'est pourquoi l'exception indique Cannot ask for request attribute - request is not active anymore), ce qui se produit lorsque votre tâche est en cours d'exécution.

Au lieu de cela, vous pouvez essayer d’injecter la UserRightsService où votre thread est créé et transmettre cette instance en tant qu’argument au thread. De cette façon, la UserRightsService devrait être créée sans problème, car la demande devrait toujours être disponible.

Néanmoins, essayer d'accéder à la RequestAttributes après la fin de la demande échouera probablement. Dans ce cas, je propose de copier toutes les valeurs nécessaires avant la fin de la demande, c’est-à-dire avant d’exécuter le thread.

Si cela ne fonctionne pas pour vous, veuillez fournir des informations supplémentaires sur la manière dont vous initialisez la variable UserRightsService dans la tâche.

Bonne chance!

P.S .: Je pense que l'annotation scope dans votre classe de thread est inutile car l'objet de tâche est créé manuellement et n'est pas géré par spring.

1
Master_ex