2016-04-08 8 views
1

там сеанс областью действия боб «Identity», который я впрыскивается в @Stateless боба, который реализует Runnable:Есть ли способ распространения SessionContext на новый поток (получение WELD-001303)?

@Stateless 
@LocalBean 
public class Test implements Runnable { 
    @Inject 
    Identity identity; 
    @Inject 
    Logger log; 

    @Override 
    public void run() { 
     log.warn("Test: " + this + " " + identity.getAccount().getId()); 
    } 
} 

Там же боб, который вызывает выше Runnable асинхронно:

@Stateless 
@LocalBean 
public class BeanContextExecutor implements Executor { 
    @Asynchronous 
    @Override 
    public void execute(Runnable command) { 
     command.run(); 
    } 
} 

и, наконец, призывание выглядит следующим образом:

@Stateless 
public class OtherBean { 
    @Inject 
    BeanContextExecutor executor; 
... 
     executor.execute(command); 
... 
} 

При запуске этого я получаю следующее сообщение об ошибке:

... 
Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped 
... 

Есть ли способ распространить SessionContext на фоновый поток?

Я также попытался отправить этот Runnable в ManagedExecutorService и даже создать прокси для него с помощью ContextService и отправить прокси-сервер, но все равно получить ту же ошибку.

Спасибо за любую помощь!

ответ

0

Как обходной путь в BeanContextExecutor я использовал BoundSessionContext создать фиктивный контекст сеанса для нового потока, а также пришлось вручную скопировать необходимый компонент сеанса, чтобы его состояние в справочной теме:

@Inject 
BoundSessionContext boundSessionContext; 
// Backed by a ConcurrentHashMap<Runnable, Identity> which stores the state of the session scoped bean before spawning a new thread 
@Inject 
GlobalExecutionContext globalExecutionContext; 
@Inject 
Instance<Identity> identityInstance; 
@Inject 
Cloner cloner; 
@Inject 
private BeanManager beanManager; 

@Asynchronous 
@Override 
public void execute(Runnable command) { 
    HashMap<String, Object> storage = new HashMap<>(); 
    boundSessionContext.associate(storage); 
    boundSessionContext.activate(); 

    Identity identity = globalExecutionContext.remove(command); 
    Bean<Identity> bean = (Bean<Identity>) beanManager.resolve(beanManager.getBeans(Identity.class)); 
    Identity localIdentity = beanManager.getContext(bean.getScope()).get(bean, beanManager.createCreationalContext(bean)); 

    cloner.copyPropertiesOfInheritedClass(identity, localIdentity); 

    command.run(); 

    boundSessionContext.invalidate(); 
    boundSessionContext.deactivate(); 
    boundSessionContext.dissociate(storage); 
} 

пример предназначен для демонстрации подхода, его можно улучшить, как поддерживающие фасоли произвольного типа. Но мне совсем не нравится этот подход. Должно быть лучшее решение проблемы распространения контекста.

Обновление: Я хотел бы сохранить идентификатор вызывающего абонента в фоновом потоке, даже если начальный сеанс истек, похоже, что это решение подходит для этого.