所以我正在使用Spring Security处理这个Spring MVC应用程序。在我的控制器花费太长时间响应的某些情况下,我一直遇到性能问题。 这是由于一种处理方法,可以根据一些用户输入处理大量数据。
现在我和我的团队一直在调整代码和处理方法,我不认为我们可以在不切片和异步执行每个切片的情况下获得更好的性能。
问题是,当我尝试将工作分割并将工作分发给子线程时,使用来自java.util.concurrent的线程池,当执行这些操作时,我会收到有关安全上下文的错误消息。
以下是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名专用用户每周使用一次。
有没有办法将securityContext传递给子线程或允许这些线程执行的任何类似线程?
由于
答案 0 :(得分:3)
当我遇到类似的问题时,我找到了两个解决方案:
解决方案1 将SecurityContextHolder的策略更改为 MODE_INHERITABLETHREADLOCAL
你可以这样做
<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 Concurrency Support Documentation
中有详细描述答案 1 :(得分:1)
我们通常会做以下事情: 在最初的spring-managed线程中
Locale locale = LocaleContextHolder.getLocale();
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
现在您需要将这两个值放在新线程可以找到的位置。然后你做:
LocaleContextHolder.setLocale( locale, true);
RequestContextHolder.setRequestAttributes( ra, true);
在你的新主题中。虽然我不确定这是否是受支持的方法,但它始终运作良好。
答案 2 :(得分:1)
也许你可以使用像InheritableThreadLocalSecurityContextHolderStrategy这样的东西?我认为它的作用是将当前线程的安全上下文复制到您在
中创建的任何线程