Spring: Inject 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>

Надеюсь, это упрощает понимание моего вопроса. ..


Мое решение

Никогда не поздно обновить собственные вопросы;). Я решил это с помощью двух разных экземпляров клиентского сеанса, одного клиентского сеанса 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! Ого, я думал, что смогу сделать это с меньшим количеством строк;) Если вы хотите узнать больше об этом подходе, не стесняйтесь обращаться ко мне.

7
задан Frank Szilinski 4 February 2012 в 15:46
поделиться