或者直接把html
MyTask類內嵌如MyBean中,這樣能夠在myBean中inject 數據庫鏈接,在內嵌類內訪問。
java ee 引入了併發執行。由於是在服務器執行併發,因此要用java ee包裏面的併發類:javax.enterprise.concurrent.ManagedScheduledExecutorService。併發是異步執行,須要實現run/call函數。因爲是異步執行,咱們實現類的建立不能用@Inject,由於這樣會致使只能建立一個實例。咱們也不能用new 建立實例,會致使沒法訪問容器中的datasource等容器提供的實例。java
這種狀況下,只能用Instance建立實例。ios
@Stateless public class MyBean { @Resource ManagedExecutorService managedExecutorService; @PersistenceContext EntityManager entityManager; @Inject Instance<MyTask> myTaskInstance; public void executeAsync() throws ExecutionException, InterruptedException { for(int i=0; i<10; i++) { MyTask myTask = myTaskInstance.get(); this.managedExecutorService.submit(myTask); } }
https://martinsdeveloperworld.wordpress.com/2014/02/25/using-java-ees-managedexecutorservice-to-asynchronously-execute-transactions/git
https://stackoverflow.com/questions/21078616/java-ee-7-injection-into-runnable-callable-objectgithub
One year has passed by since the Java EE 7 specification has been published. Now that Wildfly 8 Final has been released, it is time to take a closer look at the new features.數據庫
One thing which was missing since the beginning of the Java EE days is the ability to work with fully-fledged Java EE threads. Java EE 6 has already brought us the @Asynchronous annotation with which we could execute single methods in the background, but a real thread pool was still out of reach. But all this is now history since Java EE 7 introduced the ManagedExecutorService:json
1
2
|
@Resource
ManagedExecutorService managedExecutorService;
|
Like the well-known ExecutorService from the Standard Edition, the ManagedExecutorService can be used to submit tasks that are executed within a thread pool. One can choose if the tasks submitted should implement the Runnable or Callable interface.服務器
In contrast to a normal SE ExecutorService instance, the ManagedExecutorService provides threads that can access for example UserTransactions from JNDI in order to execute JPA transactions during their execution. This feature is a huge difference to threads started like in a SE environment.併發
It is important to know, that the transactions started within the ManagedExecutorService’s thread pool run outside of the scope of the transaction of the thread which submits the tasks. This makes it possible to implement scenarios in which the submitting thread inserts some information about the started tasks into the database while the long-running tasks execute their work within an independent transaction.app
Now, after we have learned something about the theory, let’s put our hands on some code. First we write a @Stateless EJB that gets the ManagedExecutorService injected:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Stateless
public
class
MyBean {
@Resource
ManagedExecutorService managedExecutorService;
@PersistenceContext
EntityManager entityManager;
@Inject
Instance<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();
}
}
|
The tasks that we will submit to the ManagedExecutorService are retrieved from CDI’s Instance mechanism. This lets us use the power of CDI within our MyTask class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public
class
MyTask
implements
Runnable {
private
static
final
Logger LOGGER = LoggerFactory.getLogger(MyTask.
class
);
@PersistenceContext
EntityManager entityManager;
@Override
public
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"
);
}
}
|
Here we can inject the EntityManager to persist some entities into our database. The UserTransaction that we need for the commit has to be retrieved from the JNDI. An injection using the @Resource annotation is not possible within a normal managed bean.
To circumvent the UserTransaction we could of course call the method of another EJB and use the other EJB’s transaction to commit the changes to the database. The following code shows an alternative implementation using the injected EJB to persist the entity:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
MyTask
implements
Runnable {
private
static
final
Logger LOGGER = LoggerFactory.getLogger(MyTask.
class
);
@PersistenceContext
EntityManager entityManager;
@Inject
MyBean myBean;
@Override
public
void
run() {
MyEntity myEntity =
new
MyEntity();
myBean.persit(myEntity);
}
}
|
Now we only need to utilize JAX-RS to call the functionality over a REST interface:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Path
(
"/myResource"
)
public
class
MyResource {
@Inject
private
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>"
;
}
}
|
That’s it. With these few lines of code we have implemented a fully working Java EE application whose functionality can be called over a REST interface and that executes its core functionality asynchronously within worker threads with their own transactions.
Conclusion: The ManagedExecutorService is a great feature to integrate asynchronous functionality using all the standard Java EE features like JPA and transactions into enterprise applications. I would say the waiting was worthwhile.
Example source code can be found on github.