2009-09-04 6 views
6

Je travaille donc sur cette application Spring MVC en utilisant Spring Security. J'ai rencontré un problème de performances dans certains cas où mon contrôleur prend trop de temps à répondre. Ceci est dû à une méthode de traitement qui peut prendre une énorme quantité de données à traiter, en fonction de certaines entrées utilisateur.Spring Security Child Thread Contexte

Maintenant, j'ai un peu peaufiné le code dans et autour de cette méthode de traitement avec mon équipe et je ne pense pas que nous puissions obtenir de meilleures performances sans découper et exécuter chaque tranche de façon asynchrone. Le problème est lorsque j'essaie de le découper et de distribuer le travail aux threads enfants, en utilisant un pool de threads de java.util.concurrent, j'obtiens des messages d'erreur sur le contexte de sécurité quand ceux-ci s'exécutent.

Voici un extrait du stacktrace:

Exception in thread "pool-1-thread-3" org.springframework.security.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext 
    at org.springframework.security.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:342) 
    at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:254) 
    at org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:63) 
Exception in thread "pool-1-thread-4" at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
    at $Proxy63.batchSaveCampaignpayment(Unknown Source) 
    at com.fim.pnp.controller.PaymentForm$1.run(PaymentForm.java:224) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675) 
    at java.lang.Thread.run(Thread.java:595) 
org.springframework.security.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext 
    at org.springframework.security.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:342) 
    at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:254) 
    at org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:63) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
    at $Proxy63.batchSaveCampaignPayment(Unknown Source) 
    at com.fim.pnp.controller.PaymentForm$1.run(PaymentForm.java:224) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675) 
    at java.lang.Thread.run(Thread.java:595) 
Exception in thread "pool-1-thread-5" org.springframework.security.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext 
    at org.springframework.security.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:342) 
    at org.springframework.security.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:254) 
    at org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:63) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) 
    at $Proxy63.batchSaveCampaignPayment(Unknown Source) 
    at com.fim.pnp.controller.PaymentForm$1.run(PaymentForm.java:224) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675) 
    at java.lang.Thread.run(Thread.java:595) 

Je sais que ce n'est pas une bonne pratique de reproduire des fils d'une demande ... mais nous avons couru d'idées à ce point et chaque thread de travail shouldn Ne prenez pas plus d'une poignée de secondes par nos mesures. Il est également prévu que cette fonctionnalité sera utilisée par 1 ou 2 utilisateurs dédiés une fois par semaine seulement.

Existe-t-il un moyen de transmettre le paramètre securityContext aux threads enfants ou quoi que ce soit de similaire qui permettrait à ces threads de s'exécuter?

Merci

+0

En supposant que vous utilisez un 'TaskExecutor', vous pouvez l'intégrer dans un' DelegatingSecurityContextTaskExecutor' qui prend soin de tout cela. Tout cela est expliqué dans le [guide de référence] (https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#concurrency). –

Répondre

1

Nous faisons habituellement les suivantes: Dans le fil initial géré ressort do

Locale locale = LocaleContextHolder.getLocale(); 
RequestAttributes ra = RequestContextHolder.getRequestAttributes(); 

Maintenant, vous avez besoin de mettre ces deux valeurs quelque part votre nouveau thread peut les trouver. Alors vous faites:

LocaleContextHolder.setLocale(locale, true); 
RequestContextHolder.setRequestAttributes(ra, true); 

Dans votre nouveau fil. Bien que je ne sois pas sûr si c'est la méthode supportée, ça a toujours bien fonctionné.

+0

J'ai essayé exactement ce code. fait les 2 variables finales donc je pourrais les utiliser avec le Threadpool. Toujours eu les mêmes erreurs. Je me suis assuré en imprimant le contenu des variables qu'ils ont passé correctement aux threads enfants cependant. – Lancelot

1

Peut-être que vous pourriez utiliser quelque chose comme InheritableThreadLocalSecurityContextHolderStrategy? Je pense que ce qu'il fait est de copier le contexte de sécurité du thread courant à tous les fils que vous créer au sein

+0

donnera une photo très bientôt ... merci. – Lancelot

2

J'ai trouvé deux solutions quand j'eu un problème similaire:

Solution 1 Modifier la stratégie de SecurityContextHolder à MODE_INHERITABLETHREADLOCAL

Vous pouvez le faire de telle manière

<beans:bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
    <beans:property name="targetClass" 
       value="org.springframework.security.core.context.SecurityContextHolder"/> 
    <beans:property name="targetMethod" value="setStrategyName"/> 
    <beans:property name="arguments" value="MODE_INHERITABLETHREADLOCAL"/> 
</beans:bean> 

Solution 2 Utilisez DelegatingSecurityContextRunnable, DelegatingSecurityContextExecutor ou DelegatingSecurityContextExecutor.Cette fonctionnalité est bien décrite dans Spring Concurrency Support Documentation

Questions connexes