Можно ли создать фабрику или прокси-сервер, который может решить, выполняется ли поток в (веб-запросе) или в фоновом процессе (например, планировщик), а затем в зависимости от этой информации он создает сессионный компонент или компонент-прототип?
Пример (псевдо Spring config:)
<bean id="userInfoSession" scope="session" />
<bean id="userInfoStatic" scope="prototype" />
<bean id="currentUserInfoFactory" />
<bean id="someService" class="...">
<property name="userInfo" ref="currentUserInfoFactory.getCurrentUserInfo()" />
</bean>
Надеюсь, это облегчает понимание моего вопроса ...
Мое решение
Никогда не поздно обновить собственные вопросы;). Я решил это с помощью двух разных экземпляров сеанса клиента, одного сеанса клиента 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>
ClientSession затем примет решение, является ли одноэлементная или сеансовая область:
private IClientSession getSessionAwareClientData() {
String beanName = (isInSessionContext() ? sessionScopedClientSessionBeanName : singletonScopedClientSessionBeanName);
return (IClientSession) ApplicationContextProvider.getApplicationContext().getBean(beanName);
}
Где тип сессии может быть получен через это:
private boolean isInSessionContext() {
return RequestContextHolder.getRequestAttributes() != null;
}
Все классы реализуют интерфейс под названием IClientSession. Bean-компоненты singletonScoped и sessionScoped происходят от BaseClientSession, в котором обнаружена реализация.
Тогда каждая служба может использовать сеанс клиента, то есть:
@Resource
private ClientSession clientSession;
...
public void doSomething() {
Long orgId = clientSession.getSomethingFromSession();
}
Теперь, если мы пойдем еще дальше, мы можем написать что-то вроде эмулятора для сессии. Это может быть сделано путем инициализации clientSession (который не находится в контексте запроса) одноэлементного сеанса. Теперь все сервисы могут использовать один и тот же clientSession, и мы все еще можем «эмулировать» пользователя, то есть:
clientSessionEmulator.startEmulateUser( testUser );
try {
service.doSomething();
} finally {
clientSessionEmulator.stopEmulation();
}
Еще один совет: позаботьтесь о многопоточности в экземпляре ClientSession SingletonScoped! Вау, я думал, что смогу сделать это с меньшим количеством строк;) Если вы хотите узнать больше об этом подходе, не стесняйтесь связаться со мной.