java与java ee
自Java EE 7规范发布以来已经过去了一年。 现在,Wildfly 8 Final已发布,现在是时候仔细看看这些新功能了。
自Java EE诞生以来,缺少的一件事就是能够使用成熟的Java EE线程。 Java EE 6已经为我们带来了@Asynchronous批注,通过它我们可以在后台执行单个方法,但是真正的线程池仍然遥不可及。 但是,自Java EE 7引入ManagedExecutorService以来,这一切都成为历史:
@Resource
ManagedExecutorService managedExecutorService;
像标准版中众所周知的ExecutorService一样,ManagedExecutorService可用于提交在线程池中执行的任务。 可以选择提交的任务应实现Runnable还是Callable接口。
与普通的SE ExecutorService实例相反,ManagedExecutorService提供了可以访问(例如)来自JNDI的UserTransactions的线程,以便在其执行期间执行JPA事务。 与在SE环境中启动的线程相比,此功能有很大的不同。
重要的是要知道,在ManagedExecutorService的线程池中启动的事务在提交任务的线程的事务范围之外运行。 这使得可以实现以下方案:提交线程将有关已启动任务的一些信息插入数据库,而长时间运行的任务在独立事务中执行其工作。
现在,在我们学习了一些理论之后,让我们开始编写一些代码。 首先,我们编写一个@Stateless EJB,该EJB注入了ManagedExecutorService:
@Stateless
public class MyBean {@ResourceManagedExecutorService managedExecutorService;@PersistenceContextEntityManager entityManager;@InjectInstance<MyTask> myTaskInstance;public void executeAsync() throws ExecutionException, InterruptedException {for(int i=0; i<10; i++) {MyTask myTask = myTaskInstance.get();this.managedExecutorService.submit(myTask);}}public List<MyEntity> list() {return entityManager.createQuery("select m from MyEntity m", MyEntity.class).getResultList();}
}
我们将提交给ManagedExecutorService的任务是从CDI的实例机制中检索的。 这使我们可以在MyTask类中使用CDI的功能:
public class MyTask implements Runnable {private static final Logger LOGGER = LoggerFactory.getLogger(MyTask.class);@PersistenceContextEntityManager entityManager;@Overridepublic void run() {UserTransaction userTransaction = null;try {userTransaction = lookup();userTransaction.begin();MyEntity myEntity = new MyEntity();myEntity.setName("name");entityManager.persist(myEntity);userTransaction.commit();} catch (Exception e) {try {if(userTransaction != null) {userTransaction.rollback();}} catch (SystemException e1) {LOGGER.error("Failed to rollback transaction: "+e1.getMessage());}}}private UserTransaction lookup() throws NamingException {InitialContext ic = new InitialContext();return (UserTransaction)ic.lookup("java:comp/UserTransaction");}
}
在这里,我们可以注入EntityManager来将某些实体持久化到我们的数据库中。 我们需要提交的UserTransaction必须从JNDI中检索。 在普通的受管bean中,无法使用@Resource批注进行注入。
为了规避UserTransaction,我们当然可以调用另一个EJB的方法,并使用另一个EJB的事务将更改提交到数据库。 以下代码显示了使用注入的EJB持久化实体的替代实现:
public class MyTask implements Runnable {private static final Logger LOGGER = LoggerFactory.getLogger(MyTask.class);@PersistenceContextEntityManager entityManager;@InjectMyBean myBean;@Overridepublic void run() {MyEntity myEntity = new MyEntity();myBean.persit(myEntity);}
}
现在,我们只需要利用JAX-RS通过REST接口调用该功能:
@Path("/myResource")
public class MyResource {@Injectprivate MyBean myBean;@Path("list")@GET@Produces("text/json")public List<MyEntity> list() {return myBean.list();}@Path("persist")@GET@Produces("text/html")public String persist() throws ExecutionException, InterruptedException {myBean.executeAsync();return "<html><h1>Successful!</h1></html>";}
}
而已。 通过这几行代码,我们实现了一个功能全面的Java EE应用程序,该应用程序可以通过REST接口调用其功能,并且可以通过其自己的事务在工作线程中异步执行其核心功能。
结论
ManagedExecutorService是一项很棒的功能,可以使用所有标准Java EE功能(如JPA和事务)将异步功能集成到企业应用程序中。 我会说等待是值得的。
- 示例源代码可以在github上找到。
翻译自: https://www.javacodegeeks.com/2014/03/using-java-ees-managedexecutorservice-to-asynchronously-execute-transactions.html
java与java ee