Search code examples
javaspringspring-bootdependency-injectiondagger-2

What is the Spring DI equivalent of Dagger2 Subcomponents


Dagger2 has Subcomponents https://medium.com/tompee/dagger-2-scopes-and-subcomponents-d54d58511781 for using DI with shorter lifecycles than the main application, for example if you have a job service then the service will have a Component with Subcomponents for each job.

What is the equivalent for Spring's DI framework?


Solution

  • The only possibility I can see is to use context hierarchy and to handle context with shorter lifecycle manually.

    // Does Dagger's @Subcomponent.Factory work
    public class JobExecutor {
        private final ApplicationContext mainApplicationContext;
    
        @Inject
        public JobExecutor(ApplicationContext mainApplicationContext) {
            this.mainApplicationContext = mainApplicationContext;
        }
    
        public Result execute(Job job) {
            AnnotationConfigApplicationContext jobContext = null;
            try {
                jobContext = new AnnotationConfigApplicationContext();
                jobContext.setParent(mainApplicationContext); // Provides access to common beans
                jobContext.register(SpringJobContext.class);
                jobContext.getBeanFactory().registerSingleton("job", job); // Does Dagger's @BindsInstance work
                jobContext.refresh();
                // You can access and execute one of the beans from jobContext manually or use @PostConstruct
                return jobContext.getBean(JobExecutorFromJobContext.class)
                        .execute();
            } finally {
                if (jobContext != null) {
                    jobContext.destroy();
                }
            }
        }
    
        static class JobExecutorFromJobContext {
            private final Database database; // From parent's context
            private final Job job;
    
            @Inject
            JobExecutorFromJobContext(Database database, Job job) {
                this.database = database;
                this.job = job;
            }
    
            public void execute() {
                // ...
            }
        }
    }