简体   繁体   中英

Why can't I inject dependencies with @In (using jboss seam) in a new thread from within my controller?

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:

  1. In Seam components (in your example, MyController is a component, the anonymous Runnable you create inside is not a component).
  2. Inside a Seam lifecycle. A lifecycle is either started by a JSF request, an asynchronous execution or manually by yourself.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM