Spring:根据上下文(会话/ Web或本地线程/后台进程)注入bean

Fra*_*ski 7 session spring background

是否可以创建一个工厂或代理来决定线程是在(Web)请求还是后台进程(即调度程序)中运行,然后根据该信息创建会话bean或原型bean?

示例(伪Spring配置:)

<bean id="userInfoSession" scope="session" />
<bean id="userInfoStatic" scope="prototype" />

<bean id="currentUserInfoFactory" />

<bean id="someService" class="...">
    <property name="userInfo" ref="currentUserInfoFactory.getCurrentUserInfo()" />
</bean>
Run Code Online (Sandbox Code Playgroud)

我希望这会让我的问题更容易理解......


我的解决方案

更新自己的问题永远不会迟到;).我用两个不同的客户端会话实例,一个SessionScoped客户端会话和一个SingletonScoped会话解决了它.两者都是正常豆类.

<bean id="sessionScopedClientSession" class="com.company.product.session.SessionScopedClientSession" scope="session">
    <aop:scoped-proxy />
</bean>

<bean id="singletonScopedClientSession" class="com.company.product.session.SingletonScopedClientSession" />

<bean id="clientSession" class="com.company.product.session.ClientSession">
    <property name="sessionScopedClientSessionBeanName" value="sessionScopedClientSession" />
    <property name="singletonScopedClientSessionBeanName" value="singletonScopedClientSession" />
</bean>
Run Code Online (Sandbox Code Playgroud)

然后ClientSession将决定单例或会话范围:

private IClientSession getSessionAwareClientData() {
    String beanName = (isInSessionContext() ? sessionScopedClientSessionBeanName : singletonScopedClientSessionBeanName);
    return (IClientSession) ApplicationContextProvider.getApplicationContext().getBean(beanName);
}
Run Code Online (Sandbox Code Playgroud)

可以通过以下方式收集会话类型:

private boolean isInSessionContext() {
    return RequestContextHolder.getRequestAttributes() != null;
}
Run Code Online (Sandbox Code Playgroud)

所有类都实现了一个名为IClientSession的接口.singletonScoped和sessionScoped bean都从找到实现的BaseClientSession扩展.

然后,每个服务都可以使用客户端会话,即:

@Resource
private ClientSession clientSession;

    ...

public void doSomething() {
    Long orgId = clientSession.getSomethingFromSession();
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我们更进一步,我们可以为会话编写类似于模拟器的东西.这可以通过初始化单个会话的clientSession(在请求的上下文中)来完成.现在所有服务都可以使用相同的clientSession,我们仍然可以"模拟"用户,即:

        clientSessionEmulator.startEmulateUser( testUser );
        try {
            service.doSomething();
        } finally {
            clientSessionEmulator.stopEmulation();
        }
Run Code Online (Sandbox Code Playgroud)

还有一条建议:在SingletonScoped clientSession实例中注意线程化!哇,我以为我能用更少的线条做到这一点;)如果你想了解更多有关这种方法的信息,请随时与我联系.

ska*_*man 2

你的改写确实要简单得多:)

currentUserInfoFactory可以利用RequestContextHolder.getRequestAttributes(). 如果会话存在并且与调用线程关联,那么这将返回一个非空对象,然后您可以安全地从上下文中检索会话范围的 bean。如果它返回 null,那么您应该改为获取原型范围的 bean。

它不是很整洁,但是很简单,并且应该可以工作。