【问题标题】:Inject Context (CDI/servlet) into new FutureTask Thread将上下文(CDI/servlet)注入新的 FutureTask 线程
【发布时间】:2014-08-19 14:18:41
【问题描述】:

我发现在 servlet 中创建的新线程不包含 servlet/CDI 上下文。我创建了一个 HelloWorld servlet(如下所示)来试验这个问题。在下面的示例中,您将看到我正在一个新线程 (FutureTask) 中运行“doIt()”函数。但是它返回 NULL 但是当我直接调用 'doIt()' 方法时,BeanManager 不是 NULL。

/**
 * Servlet implementation class HelloWorld
 */
@WebServlet("/HelloWorld")
public class HelloWorld extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private static Logger logger = Logger.getLogger(HelloWorld.class
            .getName());

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter writer = response.getWriter();

        writer.println("<html>");
        writer.println("<head><title>Hello World Servlet</title></head>");
        writer.println("<body>");
        writer.println("<h1>Context injection into Thread Experiment</h1>");
        try {
            // 1. This is NOT working
            new Thread(testTask).start();
            testTask.get(5000, TimeUnit.SECONDS);

            // 2. This is working
                //doIt();

        } catch (Exception e) {
            e.printStackTrace();
        }

        writer.println("<body>");
        writer.println("</html>");
        writer.close();         
    }

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                doIt();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    FutureTask<Object> testTask = new FutureTask<Object>(runnable, null);

    protected void doIt() throws Exception {
        if(getBeanManager() == null) { 
            throw new Exception( "BEAN MANAGER IS NULL"); 
        }
    }

    public static BeanManager getBeanManager() {
        try {
            InitialContext initialContext = new InitialContext();
            return (BeanManager) initialContext.lookup("java:comp/BeanManager");
        } catch (NamingException e) {
            logger.info("Couldn't get BeanManager through JNDI");
            return null;
        }
    }
}

我在网上搜索,但找不到比说有可能更好的参考。如果有人可以帮助我或为我提供一些好的指针来将上下文注入/传递到新线程中,那就太好了。

【问题讨论】:

标签: java multithreading servlets cdi futuretask


【解决方案1】:

如果您使用的是 EJB 3.1 和 Java EE 6 或更高版本,则方法上的符号 @Asynchronous 使其在单独的线程中运行并负责管理资源等。

如果您需要更多控制,正如 Kalpesh Soni 所指出的,this answer describes 如何使用 ManagedExecutorService,如果您有 Java EE 7 或更高版本。

此外,我不确定您是否真的需要 getBeanManager() 静态方法 - 仅 @EJB BeanManager beanManager;(或 @Inject)就足够了吗?

【讨论】:

    【解决方案2】:

    容器必须在请求结束后清理 servlet 对象

    线程应该创建自己的资源

    顺便说一句,如果你使用容器(tomcat/weblogic/websphere),它会做一些额外的事情来设置事务上下文,这些对你自己的线程不可用

    最好不要将线程 api 与 java ee 混合使用

    Java EE specification and multi threading

    【讨论】:

      【解决方案3】:

      我想为我在这个问题中提出的问题添加一个解决方案。借助此处给出的答案解决了这个问题。我认为,这个答案将来会帮助其他开发人员。我的主要目的是让函数超时或

      我使用 @Asyncronous 方法在单独的线程中运行,该线程也包含 CDI 上下文。通过使用.get(timeout, TimeUnit),我为运行“Future”任务的任务设置了超时参数。

      以下是 Helloworld servlet 的代码,它运行任务并在它运行的时间超过完成工作的预期时间时获取超时。

      @WebServlet(value = "/HelloWorld", asyncSupported = true)
      public class HelloWorld extends HttpServlet {
          private static final long serialVersionUID = 1L;
      
          private static Logger logger = Logger.getLogger(HelloWorld.class
                  .getName());
      
          @Inject doItWithAsync doAsync;
          @Inject doItWithAsync doAsyncTimeout;
      
          /**
           * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
           */
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              PrintWriter writer = response.getWriter();
              writer.println("<html>");
              writer.println("<head><title>Hello World Servlet</title></head>");
              writer.println("<body>");
              writer.println("<h1>New Thread with Context Experiment</h1>");
              try {
                  String ret1 = doAsync.doItAsync().get(10, TimeUnit.SECONDS);
                  writer.println("<h2>Result1: "+ ret1+"</h2>");
                  String ret2 = doAsyncTimeout.doItAsync().get(2, TimeUnit.SECONDS);
                  writer.println("<h2>Result2: "+ ret2+"</h2>");
              } catch (TimeoutException e) {
                  writer.println("<h2>Timeout Exception: "+ e.getMessage()+"</h2>");
                  e.printStackTrace();
              } catch (Exception e1) {
                  e1.printStackTrace();
              }
              writer.println("<body>");
              writer.println("</html>");
              writer.close();         
          }
      
          public static BeanManager getBeanManagerFromInitialContext() {
              try {
                  InitialContext initialContext = new InitialContext();
                  return (BeanManager) initialContext.lookup("java:comp/BeanManager");
              } catch (NamingException e) {
                  logger.info("Couldn't get BeanManager through JNDI");
                  return null;
              }
          }
      }
      

      应该在单独的线程中运行以进行超时检查的单独函数或任务在不同的类中实现为@stateless session beans。

      @Stateless
      public class doItWithAsync {
      
          @Asynchronous
          public Future<String> doItAsync() throws Exception {
              Thread.sleep(5000);
              String result;
              if(HelloWorld.getBeanManagerFromInitialContext() == null) { 
                  throw new Exception( "BEAN MANAGER IS NULL !"); 
              } else {
                  result = "OK Async!!";
              }
      
              return new AsyncResult<String>(result);
          }
      }
      

      输出如下所示:

      New Thread with Context
      Result1: OK Async!!
      Timeout Exception: JBAS014334: Task did not complete in 2 SECONDS
      

      【讨论】:

        猜你喜欢
        • 2014-02-27
        • 2014-08-30
        • 1970-01-01
        • 1970-01-01
        • 2018-08-06
        • 2012-07-29
        • 1970-01-01
        • 2015-01-21
        • 2023-04-07
        相关资源
        最近更新 更多