Is it possible and how to do Assisted Injection in Spring?

前端 未结 3 726
余生分开走
余生分开走 2021-01-04 06:52

In Guice 2 or 3, exists so called Assisted/Partial Inject described here. With this, Guice synthesizes factory implementation (implementing my interface) for my object and s

相关标签:
3条回答
  • 2021-01-04 07:26

    AFAIK you can't. In Spring you can have Instantiation using a static factory method or Instantiation using an instance factory method. With the second option you can define a bean myFactoryBean working as a factory for another bean. You can also pass construction arguments to myFactoryBean by using constructor-arg (see for example the section Using An Instance Factory Method on this blog), which gives you the equivalent of Guice-injected arguments. However, I don't know of any way to provide further arguments from context when invoking the factory method.

    0 讨论(0)
  • 2021-01-04 07:40

    The following does exactly what i asked for. Though, it does not synthesize the implementation of the factory, it is good enough as the factory has access to the injection context so that can use other beans (injectable artifacts) during construction. It uses java based @Configuration instead of XML, but it will work with XML too.

    The factory interface:

    public interface Robot {
    
    }
    
    // Implementation of this is to be injected by the IoC in the Robot instances
    public interface Brain {
        String think();
    }
    
    public class RobotImpl implements Robot {
    
        private final String name_;
        private final Brain brain_;
    
        @Inject
        public RobotImpl(String name, Brain brain) {
            name_ = name;
            brain_ = brain;
        }
    
        public String toString() {
            return "RobotImpl [name_=" + name_ + "] thinks about " + brain_.think();
        }
    }
    
    public class RobotBrain implements Brain {
        public String think() {
            return "an idea";
        }
    }
    


    // The assisted factory type
    public interface RobotFactory {
        Robot newRobot(String name);
    }
    

    // this is the Spring configuration showing how to do the assisted injection

    @Configuration
    class RobotConfig {
    
        @Bean @Scope(SCOPE_PROTOTYPE)
        public RobotFactory robotFactory() {
            return new RobotFactory() {
    
                @Override
                public Robot newRobot(String name) {
                    return new RobotImpl(name, r2dxBrain());
                }
            };
        }
    
        @Bean @Scope(SCOPE_PROTOTYPE)
        public Brain r2dxBrain() {
            return new RobotBrain();
        }
    }
    

    The test code:

    public class RobotTest {
    
        @Test
        public void t1() throws Exception {
            ApplicationContext ctx = new 
                               AnnotationConfigApplicationContext(RobotConfig.class);
            RobotFactory rf = ctx.getBean(RobotFactory.class);
            assertThat(rf.newRobot("R2D2").toString(), 
               equalTo("RobotImpl [name_=R2D2] thins about an idea"));
        }
    
    }
    

    This achieves exactly what Guice does. The tricky difference is the Scope. Spring's default scope is Singleton and Guice's is not (it is prototype).

    0 讨论(0)
  • 2021-01-04 07:41

    I finally ported Guice AsssitedInject to Spring (or maybe any jakarta.inject container if you're lucky)

    https://gitlab.com/wholesail-oss/assisted-inject

    Check it out and let me know if it helps you :)

    0 讨论(0)
提交回复
热议问题