2009-09-04 154 views
6

所以我正在使用Spring Security来开发这个Spring MVC应用程序。在我的控制器花费太长时间回应的某些情况下,我遇到了性能问题。 这是由于一种处理方法,可能需要大量的数据进行处理,基于某些用户输入。Spring安全子线程上下文

现在我已经在我的团队中对代码进行了一些调整,并且我认为如果不进行切片并异步执行每个切片,我们无法获得更好的性能。

问题是,当我尝试切片并将工作分配给子线程时,使用java.util.concurrent中的线程池,当这些线程执行时,我收到有关安全上下文的错误消息。

这里是堆栈跟踪的摘录:

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

中有很好的描述假设你正在使用'TaskExecutor',你可以把它包装在'DelegatingSecurityContextTaskExecutor'中,它负责处理所有这些事情。所有这些都在[参考指南](https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#concurrency)中解释。 – 2017-06-07 13:49:02

回答

1

我们通常执行以下操作: 在弹簧的初始管理线程做

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

现在你需要把这两个值的地方你的新的线程可以找到他们。那么你这样做:

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

在你的新线程。尽管我不确定这是否是支持的方法,但它始终运作良好。

+0

我已经试过那个代码。使2个变量最终,所以我可以使用它们与线程池。仍然有同样的错误。我已经确定通过打印他们正确传递给子线程的变量的内容。 – Lancelot 2009-09-08 22:34:28

1

也许你可以使用类似InheritableThreadLocalSecurityContextHolderStrategy的东西?我认为它是复制您在

+0

很快就会出手......谢谢。 – Lancelot 2009-09-08 22:38:22

2

我发现了两个解决方案创建的时候我也有类似的问题当前线程的线程的安全上下文是什么:

解决方案SecurityContextHolder中的1 改变策略,以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使用DelegatingSecurityContextRunnableDelegatingSecurityContextExecutorDelegatingSecurityContextExecutor。这种解释在Spring Concurrency Support Documentation