2009-09-04 7 views
6

Also arbeite ich an dieser Spring MVC-Anwendung mit Spring Security. Ich habe ein Leistungsproblem in einigen Fällen, wo mein Controller viel zu lange dauert, um zu reagieren. Dies ist auf eine Verarbeitungsmethode zurückzuführen, die aufgrund von Benutzereingaben eine große Menge an Daten verarbeiten kann.Spring Security Child Thread Kontext

Jetzt habe ich den Code ein wenig in und um diese Verarbeitungsmethode mit meinem Team optimiert und ich denke nicht, dass wir viel bessere Leistung daraus bekommen können, ohne es zu schneiden und jede Scheibe asynchron auszuführen.

Das Problem ist, wenn ich versuche, es zu zerlegen und die Arbeit an untergeordnete Threads zu verteilen, mit einem Threadpool von java.util.concurrent, bekomme ich Fehlermeldungen über den Sicherheitskontext, wenn diese ausgeführt werden. Hier

ist ein Extrakt aus der 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) 

Ich weiß es nicht gute Praxis ist Fäden von einer Anfrage zum Laichen ... aber wir haben an dieser Stelle der Ideen laufen und jeder Arbeitsthread shouldn Nach unseren Messungen brauchen wir nicht mehr als eine Handvoll Sekunden. Es wird auch erwartet, dass diese Funktion nur einmal pro Woche von 1 oder 2 dedizierten Benutzern verwendet wird.

Gibt es eine Möglichkeit, den securityContext an die untergeordneten Threads oder ähnliches zu übergeben, damit diese Threads ausgeführt werden können?

Dank

+0

gut beschrieben. Wenn Sie einen 'TaskExecutor' verwenden, können Sie ihn in einen 'DelegatingSecurityContextTaskExecutor' einfügen, der sich um all das kümmert. All dies ist im [Referenzhandbuch] (https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#concurrency) erläutert. –

Antwort

1

Wir, die in der Regel auf folgende Arten tun: In der Anfangsfeder verwalteter Thread tun

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

Jetzt müssen Sie irgendwo Ihre neuen Thread diese beiden Werte setzen sie finden können. Dann tun Sie:

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

In Ihrem neuen Thread. Obwohl ich nicht sicher bin, ob dies die unterstützte Methode ist, hat es immer gut funktioniert.

+0

Ich habe genau diesen Code ausprobiert. habe die 2 Variablen endgültig gemacht, damit ich sie mit dem Threadpool verwenden konnte. Immer noch die gleichen Fehler. Ich habe dafür gesorgt, dass der Inhalt der Variablen, die sie korrekt an die untergeordneten Threads übergeben haben, gedruckt wird. – Lancelot

1

Vielleicht könnten Sie etwas wie InheritableThreadLocalSecurityContextHolderStrategy verwenden? Ich denke, was es tut, ist den Sicherheitskontext des aktuellen Threads auf alle Threads Sie innerhalb

+0

wird das sehr bald geben ... danke. – Lancelot

2

Ich fand zwei Lösungen erstellen zu kopieren, wenn ich hatte ein ähnliches Problem:

Lösung 1 ändern Strategie von SecurityContextHolder zu MODE_INHERITABLETHREADLOCAL

Sie es

in einer solchen Art und Weise tun kann
<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> 

Lösung 2 Verwenden DelegatingSecurityContextRunnable, DelegatingSecurityContextExecutor oder DelegatingSecurityContextExecutor.Diese Lösung ist in Spring Concurrency Support Documentation