问题
We want to optimize our application. There is some streight linear work going on, that can be executed in multiple threads with smaller working sets.
Our typical service is accessed using the @Inject
annotation from within our CDI-managed beans. Also such a service could have it's own dependencies injected, i.e.:
public class MyService {
@Inject
private OtherService otherService;
@Inject
private DataService1 dataService1;
...
public void doSomething() {
...
}
}
Because I can not use @Inject
inside the class implementing Runnable
. (It's not container managed.) I tried to pass the required services to the class before starting the thread. So, using something like this, makes the service instance (myService
) available within the thread:
Class Thread1 implements Runnable{
private MyService myService
public Thread1(MyService myService){
this.myService = myService;
}
public void run(){
myService.doSomething();
}
}
Following the call-hierarchy the call to doStometing()
is fine, because a reference to myService
has been passed. As far as I understand CDI, the injection is done the moment the attribute is accessed for the first time, meaning, when the doStomething()
method tries to access either otherService
or dataService1
, the injection would be performed.
At that point however I receive an exception, that there is no context available.
I also tried to use the JBossThreadExecuter
class instead of Plain-Threads - it leads to the very same result.
So the question would be, if there is a nice way to associate a context (or request) with a created Thread
?
For EJB-Beans, I read that marking a method with @Asynchronous
will cause the method to be run in a managed thread which itself will be wired to the context. That would basically be exactly what I'm searching for.
Is there a way to do this in CDI?
Or is there any way to obtain a context
from within a unmanaged thread?
回答1:
Weld allows programmatic context management, (there's an example in the official docs).
But before you go this way give EJBs a chance )
@Async invocation functionality is there exactly for your case. And as a bonus you'll get timeout interception and transaction management.
回答2:
When you kick off an async process, your @RequestScoped
and @SessionScoped
objects are no longer in scope. That's why you get resolution errors for the injected @RequestScoped
objects. Using @Stateless
without a CDI scope is essentially @Dependent
. You can use @ApplicationScoped
objects or if you're on CDI 1.1 you can start up @TransactionScoped
.
回答3:
You have to use JavaEE 7 feature, the managed executor. So it will provide a context for your runnable. I'm not sure if your JBoss version is JavaEE 7 compatible. At least Glassfish 4 is, and that approach works. See details here
回答4:
Easiest Solution one can think of is Ejb Async.
They are powerful, does the job and most importantly the concurrency is handled by the container(which could be an issue at some point of time if its not properly managed).
Just a simple use case lets say if we have written a rest service and each request spawns 10 threads(ex using CompletableFuture or anything) to do some long processing tasks and for an instance if 500 requests are made then how will the threads be managed, how the app behaves, does it waits for a thread from the thread pool, what is the timeout period, etc etc and to add to our comfort what happens when the threads are Deamon Threads. We can avoid these overheads to some extent using EJBs.
Its always a good thing to have a friend from the technical services team to help us with all these container specific implementations.
来源:https://stackoverflow.com/questions/21284191/cdi-multithreading