【发布时间】:2015-05-18 10:50:47
【问题描述】:
我正在构建一个 Spring Boot Web 应用程序,并且我有一个请求范围的 bean。
我正在使用 Spring Security,并且需要访问过滤器链中的请求范围 bean(DispatcherServlet 之前),所以我注册了 RequestContextListener 以使其可用 - 一切正常:我可以自动装配将作用域 bean 请求到我的过滤器链中并可以使用它。但是,似乎请求范围的 bean 在 Spring 安全过滤器链之后被重新初始化。
以下日志:
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
May 18 06:19:40 DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] Checking match of request : '/app/test'; against '/logout'
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 5 of 12 in additional filter chain; firing Filter: 'SystemSecurityFilter'
May 18 06:19:40 DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] Checking match of request : '/app/test'; against '/________site-memory-status'
May 18 06:19:40 DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] Checking match of request : '/app/test'; against '/________site-monitor'
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 6 of 12 in additional filter chain; firing Filter: 'RequestScopeFilter'
May 18 06:19:40 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] Creating instance of bean 'scopedTarget.requestScopedBean'
May 18 06:19:40 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] Returning cached instance of singleton bean 'application'
May 18 06:19:40 INFO [com.test.app] Creating RequestScopedBean.
May 18 06:19:40 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] Finished creating instance of bean 'scopedTarget.requestScopedBean'
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
May 18 06:19:40 DEBUG [org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy] Delegating to org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
May 18 06:19:40 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] Secure object: FilterInvocation: URL: /app/test; Attributes: [permitAll]
May 18 06:19:40 DEBUG [org.springframework.security.access.vote.AffirmativeBased] Voter: org.springframework.security.web.access.expression.WebExpressionVoter, returned: 1
May 18 06:19:40 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] Authorization successful
May 18 06:19:40 DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] RunAsManager did not change Authentication object
May 18 06:19:40 DEBUG [org.springframework.security.web.FilterChainProxy] /app/test reached end of additional filter chain; proceeding with original chain
May 18 06:19:40 INFO [com.test.app] Creating RequestScopedBean.
May 18 06:19:40 DEBUG [org.springframework.web.servlet.DispatcherServlet] DispatcherServlet with name 'dispatcherServlet' processing GET request for [/app/test]
May 18 06:19:40 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] Returning cached instance of singleton bean 'AppController'
您将看到“Creating RequestScopedBean”这一行——它记录在我的请求范围 bean 的构造函数中,并被调用两次——一次是在我的自定义过滤器被调用时 (RequestScopeFilter),然后在将过滤器链移交给DispatchServlet。这是预期的行为吗?它更早可用似乎很奇怪,但仍然在DispatcherServlet 重新初始化 - 假设它只是可配置的,但在 RequestContextListener 上看不到任何选项。我想也许我应该换成RequestContextFilter 并使用setThreadContextInheritable 方法来看看是否能达到我想要的效果,但找不到任何关于何时使用另一种方法的明确建议。
更新
好的,这是我一周内第二次在 SO 上成为白痴 - 实际上 Spring 并没有两次初始化 bean,而是我的过滤器被执行了两次,并且我对请求范围 bean 所做的更改正在记录相同的消息。
下一个问题是为什么过滤器会执行两次?我唯一的猜测是因为我已将过滤器注册为 Spring @Bean 并将其显式添加到我的 Spring 过滤器链中。我应该更改为实现OncePerRequestFilter,还是有其他配置可以阻止它作为我的 Spring Security 过滤器链的一部分执行?
【问题讨论】:
-
奇怪的是,第一行调用了一个 bean 创建(在 Creating instance 和 Finished Creating instance 之间),而另一行则没有.但在不知道什么是 RequestScopeFilter 或 RequestScopedBean 的情况下,我不能说更多。
-
谢谢@SergeBallesta - 我已经更新了问题,主要是我的错误,但现在导致了另一个问题..
-
如果您将其添加为
@Bean,spring boot 将检测到它并将其注册为常规过滤器,现在如果您还将其添加到 spring 安全链中,它将执行两次。最简单的方法是删除@Bean注释。 -
我需要在我的请求范围 bean 中自动装配到过滤器,如果过滤器没有注册为 bean,这将不起作用。我已更改为扩展 OncePerRequestFilter 并且似乎已修复它。
标签: java spring spring-mvc spring-boot