开发者

Guice runtime dependency parameters reinjection

A question about Guice. I'm still learning it, but I can understand the fundamentals.

This question was already asked a couple of times on the net, but never with a concrete answer(none that I could find).

Say I have a situation like on the picture(a similar example was somewere on the net).

Guice runtime dependency parameters reinjection

public class Dog {}

public class Walk implements Walkable {
    private final Dog dog;
    private final boolean leash;

    @Inject
    public Walk(Do开发者_开发问答g dog, @Assisted boolean leash) {
        this.dog = dog;
        this.leash = leash;
    }

    public void go() {
    }
}

public interface Walkable {
    void go();
}

public interface WalkFactory {
    Walk create(boolean leash);
}

public class AssistedMain {
    public static void main(String[] args) {
        Injector i = Guice.createInjector(new AbstractModule() {
            protected void configure() {

                install(new FactoryModuleBuilder().
                        implement(Walkable.class, Walk.class).
                        build(WalkFactory.class));
            }
        });

        Walk walk = i.getInstance(WalkFactory.class).create(true);
    }
}

That's all great. But the question is - can I, somehow, reinject that object instance to the "container"(injector) to be used on the classes that rely on this dependency.

So, lets add a interface Person, class PersonImpl.

Guice runtime dependency parameters reinjection

The new classes source are:

public interface Person {
    void walkDog();
}

public class PersonImpl implements Person {
    private Walkable walkable;

    @Inject
    public PersonImpl(Walkable walkable) {
        this.walkable = walkable;
    }

    public void setWalkable(Walkable walkable) {
        this.walkable = walkable;
    }

    public void walkDog() {
        walkable.go();
    }
}

So, the question is - am I, somehow able to actually inject this particular instance into the added object. This is a simple example, but we can presume there are 10 levels of classes below this one.

The solution I found is not very flexible. Something like:

Injector i = Guice.createInjector(new SimpleModule(false, dog));

And then bind to concrete instance. That's not very dynamic. Basically, every time I need a different runtime/dynamic parameter I have to recreate the injector.

The Provider<T> is nice, the FactoryModuleBuilder helps, but how can I inject the objects back?

Are there more dynamic solutions to this problem?

Thanks.


MPierce - agreed. Ill try to explain the way i visualized the problem(you can correct me if im wrong).

Being originaly derived from a "service locator" pattern, the idea that it can manage more than services is optimistic to say the least.

We could split the application into Service and Data classes, or you could say that we have application and infrastructure code - "Dependency Injection", a great book.

So, basicly, dependecy injection, and dependency injection frameworks in general are great. For solving infrastructure, or "service" code.

Any dynamic(runtime) parameters being injected into the Container/Injector are basicly forcing you to end the object graph.

For example, we have the folowing design:

Guice runtime dependency parameters reinjection

EmailMessage is a runtime parameter. It can be "injected" into email service outside the Container/Injector, but it ends the object graph. If we want to request EmailDispatcher, after we injected the EmailMessage into EmailService(which is, I repeat, done outside injector), we could no longer fetch EmailDispatcher from the injector.

Then, you could redesign your model so it "fits" into the Container/Injector concept of dynamic parameters.

Guice runtime dependency parameters reinjection

But then again, you forced the design, and suddenly, EmailDispatcher has too many responsibilites. It could be used in such a context, where you dont have many infrastructure classes.

Guice runtime dependency parameters reinjection

And when you have a design like you have in the third example picture, you cannot use the Injector/Container to fetch you a NextService3 instance(nor any below the level of EmailDispatcher).

The problem being - if you have any dynamic(runtime) parameters, you can only use dependency injection for classes above the class that requires a dynamic parameter, you can forget the classes below.

Phew.

Correct?


Part of the problem depends on how you're resolving that 'false' is the thing you want to set for the leash field. Is that coming from config data or what?

A provider method may be helpful...

class FooModule extends AbstractModule {
...
    @Provides
    Walkable getWalkable(Dog dog) {
        boolean leash = getBooleanFromSomewhere();
        return new Walk(dog, leash);
    }
}

If you can clarify where that boolean is coming from, it'll help me to understand what type of approach is applicable.


You can use custom scopes, much like when using guice servlets. That way you can create your instance, and then seed it in the injector.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜