使用Java EE的ManagedExecutorService异步执行事务
自Java EE 7規范發布以來已經過去了一年。 現在,Wildfly 8 Final已發布,現在是時候仔細看看這些新功能了。
自從Java EE時代開始以來就缺少的一件事是能夠使用成熟的Java EE線程。 Java EE 6已經為我們帶來了@Asynchronous批注,通過它我們可以在后臺執行單個方法,但是真正的線程池仍然遙不可及。 但是,自Java EE 7引入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 EE的ManagedExecutorService异步执行事务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 容声冰箱怎么设置(容声冰箱怎么设置冷冻)
- 下一篇: 为什么要在Java SE 7的数字中使用