Java 将上下文(CDI/servlet)注入新的FutureTask线程

Java 将上下文(CDI/servlet)注入新的FutureTask线程,java,multithreading,servlets,cdi,futuretask,Java,Multithreading,Servlets,Cdi,Futuretask,我发现在servlet中创建的新线程不包含servlet/CDI上下文。我创建了一个HelloWorldservlet(如下所示)来试验这个问题。在下面的示例中,您将看到我正在一个新线程(FutureTask)中运行'doIt()'函数。但它返回NULL,但当我直接调用'doIt()'方法时,BeanManager不为NULL /** * Servlet implementation class HelloWorld */ @WebServlet("/HelloWorld") public

我发现在servlet中创建的新线程不包含servlet/CDI上下文。我创建了一个HelloWorldservlet(如下所示)来试验这个问题。在下面的示例中,您将看到我正在一个新线程(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;
        }
    }
}
/**
*Servlet实现类HelloWorld
*/
@WebServlet(“/HelloWorld”)
公共类HelloWorld扩展了HttpServlet{
私有静态最终长serialVersionUID=1L;
私有静态记录器=Logger.getLogger(HelloWorld.class
.getName());
/**
*@参见HttpServlet#doGet(HttpServletRequest请求,HttpServletResponse响应)
*/
受保护的void doGet(HttpServletRequest请求,HttpServletResponse响应)抛出ServletException,IOException{
PrintWriter=response.getWriter();
writer.println(“”);
println(“helloworldservlet”);
writer.println(“”);
println(“上下文注入线程实验”);
试一试{
//1.这不起作用
新线程(testTask.start();
获取(5000,时间单位。秒);
//2.这是有效的
//doIt();
}捕获(例外e){
e、 printStackTrace();
}
writer.println(“”);
writer.println(“”);
writer.close();
}
Runnable Runnable=新的Runnable(){
@凌驾
公开募捐{
试一试{
doIt();
}捕获(例外e){
e、 printStackTrace();
}
}
};
FutureTask testTask=新的FutureTask(可运行,空);
受保护的void doIt()引发异常{
如果(getBeanManager()==null){
抛出新异常(“BEAN管理器为空”);
}
}
公共静态BeanManager getBeanManager(){
试一试{
InitialContext InitialContext=新的InitialContext();
return(BeanManager)initialContext.lookup(“java:comp/BeanManager”);
}捕获(NamingE例外){
info(“无法通过JNDI获取BeanManager”);
返回null;
}
}
}

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

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

线程应该创建自己的资源

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

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


如果您使用的是EJB3.1和JavaEE6或更高版本,则方法上的符号使其在单独的线程中运行,并负责管理资源等

如果您需要更多的控制,正如Kalpesh Soni所指出的,如果您拥有JavaEE7或更高版本,如何使用


另外,我不确定您是否真的需要这个
getBeanManager()
static方法——不仅仅是
@EJB-BeanManager-BeanManager
(或
@Inject
)足够了吗?

我想为我在这个问题中提出的问题添加一个解决方案。这个问题在这里给出的答案的帮助下得以解决。我认为,这个答案将在将来帮助其他开发者。我的主要目标是获得一个函数或函数的超时

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

下面是Helloworld servlet的代码,该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
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