首页 > 解决方案 > Dagger-2: How to wire up my program, if I have to inject dependencies at runtime?

问题描述

I think this is a very fundamental question, where I couldn't find a answer for. My setup is as following:

My main component (used to make dependencies available to the entire object graph, e.g. Jackson's ObjectMapper.class, that is provided by the ModuleUtils.class)

@Component(modules = {
    ModuleApplication.class,
    ModuleUtils.class
})
public interface ComponentApplication {
   ComponentSocketManager.Builder componenetSocketManagerBuilder();
}

My subcomponent (used to create the SocketManager)

@Subcomponent(modules = ModuleSocketManager.class)
public interface ComponentSocketManager {

   //Subcomponent is used to create a SocketManager
   SocketManager socketManager();

   @Subcomponent.Builder
   interface Builder {

    //SocketManager requires a Socket to work with, which is only 
    //available at runtime
    @BindsInstanceBuilder socket(Socket socket);
    ComponentSocketManager build();
    }
}

At runtime of the program, sockets are spawned and new SocketManagers can be instantiated with the help of Dagger2:

Socket socket = this.serverSocket.accept();
//Here the wiring of the object graph is somehow interrupted, as I need
//to inject objects at runtime, that are required for the wiring process
SocketManager sm = DaggerComponentApplication.create()
                     .componenetSocketManagerBuilder()
                     .socket(socket) //inject the socket at runtime
                     .build()
                     .socketManager();

//I don't want to wire my app manually. Dagger should do the wiring of the
//entire object graph, not only up to the point where I inject at runtime
AppBusinessLogic appBusinessLogic = ... //some deeply nested wiring
MyApp app = new MyApp(sm, appBusinessLogic);
Thread thread = new Thread(app);   //new thread for every client
thread.start();

The problem is how I manually intervene into the "wiring process" of dagger2 and how AppBusinessLogic is created. AppBusinessLogic basically represents the entire program and is a deeply nested object graph.
What I want:
Initialize the entire program at startup (without "breaking" the wiring process). Rather inject dependencies at runtime into the completed object graph that contains some sort of "placeholders" for the runtime dependencies.
Why do I want that?
I want to reuse dependencies from the parent components. E.g. in the example above ComponentApplication has an ObjectMapper-dependencies. How can I reuse exactly that instance for my "appBusinessLogic" object? Of course I could have sth like a ComponentAppBusinessLogic, that inherits from ComponentApplication. However using ComponentAppBusinessLogic to create a "appBusinessLogic"-object would result into a new ObjectMapper-dependency?
So, how can I wire up the entire program at initialization phase and use dagger's inheritance concept? Or how do I avoid interrupting the wiring process of the entire program when I have dependencies at runtime to inject?

标签: javadependency-injectiondagger-2

解决方案


当您的父组件具有绑定时,ObjectMapper您的子组件就可以访问它。这意味着您可以在子组件中创建配置方法,例如...

@Subcomponent(modules = {SubcomponentModule.class})
public interface MySubcomponent {
    ...
    ObjectMapper objectMapper(); // e.g. singleton bound by parent component
    ...
}

并且您可以依赖子组件模块中的此类对象

@Module
public class SubcomponentModule {
    @Provides
    Foo provideFoo(ObjectMapper objectMapper) {
        return new Foo(objectMapper);
    }
}

另请参阅Dagger 子组件


推荐阅读