自从这个问题得到回答以来,春天的世界发生了很多变化。Spring简化了将当前用户放入控制器的过程。对于其他豆类,Spring采纳了作者的建议,简化了“SecurityContextHolder”的注入。更多细节在评论中。
这是我最终采用的解决方案。我不想在我的控制器中使用,而是想注入一些在引擎盖下使用的东西,但从我的代码中抽象出那个类似单例的类。除了滚动我自己的界面之外,我没有找到其他方法,就像这样:SecurityContextHolder
SecurityContextHolder
public interface SecurityContextFacade {
SecurityContext getContext();
void setContext(SecurityContext securityContext);
}
现在,我的控制器(或任何POJO)将如下所示:
public class FooController {
private final SecurityContextFacade securityContextFacade;
public FooController(SecurityContextFacade securityContextFacade) {
this.securityContextFacade = securityContextFacade;
}
public void doSomething(){
SecurityContext context = securityContextFacade.getContext();
// do something w/ context
}
}
而且,由于接口是解耦点,因此单元测试非常简单。在这个例子中,我使用Mockito:
public class FooControllerTest {
private FooController controller;
private SecurityContextFacade mockSecurityContextFacade;
private SecurityContext mockSecurityContext;
@Before
public void setUp() throws Exception {
mockSecurityContextFacade = mock(SecurityContextFacade.class);
mockSecurityContext = mock(SecurityContext.class);
stub(mockSecurityContextFacade.getContext()).toReturn(mockSecurityContext);
controller = new FooController(mockSecurityContextFacade);
}
@Test
public void testDoSomething() {
controller.doSomething();
verify(mockSecurityContextFacade).getContext();
}
}
接口的默认实现如下所示:
public class SecurityContextHolderFacade implements SecurityContextFacade {
public SecurityContext getContext() {
return SecurityContextHolder.getContext();
}
public void setContext(SecurityContext securityContext) {
SecurityContextHolder.setContext(securityContext);
}
}
最后,生产中的 Spring 配置如下所示:
<bean id="myController" class="com.foo.FooController">
...
<constructor-arg index="1">
<bean class="com.foo.SecurityContextHolderFacade">
</constructor-arg>
</bean>
Spring,一个包含所有事物的依赖注入容器,似乎没有提供一种注入类似东西的方法,这似乎有点愚蠢。我知道是从阿杰吉继承的,但仍然如此。问题是,它们非常接近 - 如果只有一个 getter 来获取底层实例(这是一个接口),你可以注入它。事实上,我甚至为此打开了一个Jira问题。SecurityContextHolder
SecurityContextHolder
SecurityContextHolderStrategy
最后一件事 - 我刚刚大大改变了我以前在这里的答案。如果您好奇,请查看历史记录,但是,正如一位同事向我指出的那样,我之前的答案在多线程环境中不起作用。默认情况下,使用的基础是 的实例,它将 s 存储在 中。因此,在初始化时将 直接注入 Bean 并不一定是一个好主意 - 在多线程环境中,可能需要每次都从 中检索它,因此检索正确的 bean。SecurityContextHolderStrategy
SecurityContextHolder
ThreadLocalSecurityContextHolderStrategy
SecurityContext
ThreadLocal
SecurityContext
ThreadLocal