gpt4 book ai didi

java - 将数据库 session 注入(inject)服务的调度程序的 CDI 范围

转载 作者:太空宇宙 更新时间:2023-11-04 07:08:02 24 4
gpt4 key购买 nike

上下文

我正在开发一个 Web 应用程序,我尝试在其中集成 Vaadin 和 DB4O 以及在 TomEE 容器中运行的 CDI。为了进行数据库事务,我创建了 ServletFilter,它拦截所有请求并在请求结束时提交或回滚。

@WebFilter("/*")
public class DBTransactionHandler implements Filter {

@Inject
SessionImpl sessionImpl;

@Override
public void destroy() {
// TODO Auto-generated method stub
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
boolean hadException = false;
try {
chain.doFilter(request, response);
} catch (RuntimeException ex) {
hadException = true;
throw ex;
} finally {
if (sessionImpl != null) {
if (hadException || sessionImpl.isRollbackOnly()) {
sessionImpl.rollback();
} else {
sessionImpl.commit();
}
sessionImpl.close();
}
}
}

@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub

}

}

我有一个 SessionImpl,它被设置为@RequestScoped。通过这个,我试图实现所有在处理 HTTP 请求时需要使用数据库的服务,然后它们应该获得相同的实例,因此它将在相同的数据库事务中执行。

/**
* http://community.versant.com/documentation/reference/db4o-8.0/java/reference/Content/platform_specific_issues/web/servlets.htm
*/
@RequestScoped
public class SessionImpl implements Session {

@Inject
DBConnectionFactory connectionFactory;

private boolean rollbackOnly;

private ObjectContainer delegate;

@PostConstruct
public void init() {
delegate = connectionFactory.getConnection().ext().openSession();
}
//.... many other database related methods
}

我的所有服务均源自 AbstractService,因此它们可以立即启动工作 session 。

public class AbstractService {

@Inject
protected BeanManager beanManager;

@Inject
protected Session db;

}

这就是我目前所拥有的,这就是我的问题:

问题

在我的网络应用程序中,我需要创建一个调度程序组件。预定的作业将使用我已有的相同服务。由于 SessionImpl@RequestScoped 并且我在计划作业中没有 HTTP 请求,因此无法注入(inject) SessionImpl。

  • 我可以以某种方式从调度程序线程激活 RequestScope 上下文吗?

我试图做的是创建一个自定义范围@SchedulerScoped。这将在调度程序开始执行作业之前激活。这种方法的问题是,当我向 SessionImpl 添加第二个作用域时,我的应用程序不再部署:

SEVERE: CDI Beans module deployment failed
org.apache.webbeans.exception.WebBeansConfigurationException: Managed Bean implementation class : org.reluxa.db.SessionImplstereotypes must declare the same @Scope annotations.
at org.apache.webbeans.config.DefinitionUtil.defineScopeType(DefinitionUtil.java:390)
at org.apache.webbeans.component.creation.AbstractBeanCreator.defineScopeType(AbstractBeanCreator.java:145)
at org.apache.webbeans.util.WebBeansUtil.defineManagedBean(WebBeansUtil.java:2548)
at org.apache.openejb.cdi.BeansDeployer.defineManagedBean(BeansDeployer.java:552)
at org.apache.openejb.cdi.OpenEJBLifecycle.deployManagedBeans(OpenEJBLifecycle.java:407)

最佳答案

这是一个有趣的问题。我建议将以下内容作为解决方案的概要我实际上还没有尝试过,因此需要进行一些调整:

  • 使 SessionImpl 非 CDI:删除 @RequestScoped@Inject
  • 使用创建 Session 的生产者方法创建一个 CDI bean,如下所示:

    // I believe it should be @ApplicationScoped
    public class SessionProducer {
    private ThreadLocal<Session> currentSession;
    @Produces Session makeSession() {
    return currentSession.get();
    }
    public ThreadLocal<Session> getCurrentSessionThreadLocal() {
    return currentSession;
    }
    }

    因此 session 驻留在 ThreadLocal 中,生产者只是从那里获取它。谁把它放在那里?

  • 修改过滤器以将Session放入和删除ThreadLocal中:

    @WebFilter("/*")
    public class DBTransactionHandler implements Filter {

    @Inject
    DBConnectionFactory connectionFactory;

    @Inject
    SessionProducer sessionProducer;

    ...

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    boolean hadException = false;
    try {
    SessionImpl sessionImpl = new SessionImpl();
    sessionImpl.setConnectionFactory(connectionFactory);
    sessionProducer.getCurrentSessionThreadLocal().set(sessionImpl);
    // here you probably want to call sessionImpl.init();
    chain.doFilter(request, response);
    } catch (RuntimeException ex) {
    hadException = true;
    throw ex;
    } finally {
    if (sessionImpl != null) {
    if (hadException || sessionImpl.isRollbackOnly()) {
    sessionImpl.rollback();
    } else {
    sessionImpl.commit();
    }
    sessionImpl.close();
    sessionProducer.getCurrentSessionThreadLocal().set(null);
    }
    }
    }

    ...
    }

    到目前为止,您的 Web 配置应该可以像以前一样工作。根据需要进行测试和调整。 (请测试每个线程仅生成一个 session 。)

  • 现在您必须在调度程序中重复 SessionImpl 创建和销毁仪式。这样,服务仍然会看到有效的Session,而不需要请求范围。这个“仪式”可能会被排除在外(例如,执行这些操作的调度程序的 CDI 或 EJB 拦截器是可重用的,并且不会用这样的系统逻辑污染组件的业务逻辑)。

关于java - 将数据库 session 注入(inject)服务的调度程序的 CDI 范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21039429/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com