I am having some troubles with dependency injection stuff, as I am really new to Seam I might be doing something in a wrong way!
I need to inject dependencies on a new thread which is fired from within a controller - I get no exceptions but they simply come null
. First I tried simply reusing d1
(see below) within the thread but It was null
, then I had this idea, to annotate this object again with @In
... Unfortunately the same happened (got null)!!!
@Scope(ScopeType.CONVERSATION)
@Name("myController")
public class MyController{
@In(create = true)
private Dependency1 d1; //ok, gets injected with no problems!
public void importantMethod(){
//this part of the method is important and is fast
//but below comes an expensive part that takes some minutes
new Thread(new Runnable(){
@In(create = true)
private Dependency1 anotherD1; //I still need d1 here!!!
@Override
public void run(){
//I want to run expensive code here.
//A new thread is required in order to leave
//the visitor free to go else where on the web site
//First trial was to make d1 final and simply use it here!
//d1.doExpensiveStuff();
};
}).start();
}
}
Does anyone have any idea on why this is happening? Are there any good practices when working with DI/Seam/Threading?
Injection happens only:
MyController
is a component, the anonymous Runnable
you create inside is not a component).So, you cannot use @In
inside your thread because it is not a component and Seam will not intercept calls to it. To get hold of components within the asynchronous thread, you need to use the Seam API to start the lifecycle and get the components you need:
@Scope(ScopeType.CONVERSATION)
@Name("myController")
public class MyController {
@In(create = true)
private transient Dependency1 d1;
public void importantMethod() {
new Thread(new Runnable() {
@Override
public void run() {
LifeCycle.beginCall(); // Start the Seam lifecycle
Dependency1 d1 = (Dependency1) Component.getInstance("dependency1");
d1.doExpensiveStuff();
LifeCycle.endCall(); // Dispose the lifecycle
}
}).start();
}
}
Seam provides the @Asynchronous
annotation that does just what you want here. If this annotation is used in a method of a Seam component, the method will be executed in a background thread (taken from a Seam-owned threadpool). Note that the asynchronous method will be able to use injected dependencies as if it was a normal Seam call:
@Name("myBackgroundWork")
public class MyBackgroundWork {
@In private transient Dependency1 d1;
@Asynchronous
public void runInBackground() {
d1.doExpensiveStuff();
}
}
Then in MyController
you can call the asynchronous method which will start the background work and return immediately:
@Scope(ScopeType.CONVERSATION)
@Name("myController")
public class MyController {
@In(create = true)
private MyBackgroundWork myBackgroundWork;
public void importantMethod() {
// Execution will return immediately and thread will start
myBackgroundWork.runInBackground();
}
}
More info here:
http://docs.jboss.org/seam/2.2.2.Final/reference/en-US/html/jms.html#d0e21609