Java 将上下文(CDI/servlet)注入新的FutureTask线程
我发现在servlet中创建的新线程不包含servlet/CDI上下文。我创建了一个HelloWorldservlet(如下所示)来试验这个问题。在下面的示例中,您将看到我正在一个新线程(FutureTask)中运行'doIt()'函数。但它返回NULL,但当我直接调用'doIt()'方法时,BeanManager不为NULLJava 将上下文(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 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