问题描述
所以我正在使用Spring Security来开发这个Spring MVC应用程序.在某些情况下,我的控制器的响应时间过长,我遇到了性能问题.这是由于一种处理方法,根据某些用户输入,该方法可能需要处理大量数据.
So I'm working on this Spring MVC application using Spring Security. I've been hitting a performance problem in some instances where my controller is taking way too long to respond.This is due to a processing method that can take a huge amount of data in to process, based on some user input.
现在,我一直在与我的团队一起对该处理方法进行一些微调,我认为如果不对它进行切片和异步执行每个切片,我们将无法从中获得更好的性能.
Now I've been tweaking the code a bit in and around that processing method with my team and I don't think we can get much better performance out of that without slicing it and executing each slice asynchronously.
问题是,当我尝试使用java.util.concurrent中的线程池对它进行切片并将工作分配给子线程时,执行这些消息时会收到有关安全上下文的错误消息.
The problem is when I try to slice it and distribute the work to child threads, using a threadpool from java.util.concurrent, I get error messages about the security context when those execute.
这是stacktrace的摘录:
Here is an extract of the 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)
我知道从请求中生成线程不是一个好习惯……但是我们在这一点上已经花光了,根据我们的测量,每个工作线程所花费的时间不应超过几秒钟.另外,预计每周只有1个或2个专用用户可以使用此功能.
I know it's not good practice to spawn threads from a request... but we've ran out of ideas at this point and each worker thread shouldn't take more than a handful of seconds by our measurements. Also it is expected that this feature is going to be used by 1 or 2 dedicated users once a week only.
是否有一种方法可以将securityContext传递给子线程或类似的允许子线程执行的事情?
Is there a way to pass the securityContext to the child threads or anything similar that would allow those threads to execute?
谢谢
推荐答案
当我遇到类似的问题时,我发现了两个解决方案:
I found two solutions when I had a similar problem:
解决方案1 将SecurityContextHolder的策略更改为 MODE_INHERITABLETHREADLOCAL
Solution 1Change strategy of SecurityContextHolder to MODE_INHERITABLETHREADLOCAL
您可以通过这种方式完成
You may do it in such way
<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>
解决方案2 使用 DelegatingSecurityContextRunnable , DelegatingSecurityContextExecutor 或 DelegatingSecurityContextExecutor . Spring并发支持文档中对此解决方案进行了很好的描述.
这篇关于Spring Security子线程上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!