Можно ли создать фабрику или прокси-сервер, который может решить, запущен ли поток в (Интернет) Запрос или фоновый процесс (например, планировщик), а затем, в зависимости от этой информации, он создает компонент сеанса или компонент-прототип?
Пример (псевдо-конфигурация 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>
Надеюсь, это упрощает понимание моего вопроса. ..
Мое решение
Никогда не поздно обновить собственные вопросы;). Я решил это с помощью двух разных экземпляров клиентского сеанса, одного клиентского сеанса SessionScoped и одного сеанса SingletonScoped. Оба являются обычными bean-компонентами.
<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. И singletonScoped, и sessionScoped bean-компоненты расширяются от 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! Ого, я думал, что смогу сделать это с меньшим количеством строк;) Если вы хотите узнать больше об этом подходе, не стесняйтесь обращаться ко мне.