Dependency injection 注入实例化无法控制的类的最佳方法是什么?

Dependency injection 注入实例化无法控制的类的最佳方法是什么?,dependency-injection,guice,code-migration,Dependency Injection,Guice,Code Migration,我是Guice的新手,所以希望这不是一个明显的问题 我正在处理一个框架,它使用反射动态实例化我的一个应用程序类(我们称之为C),因此我无法控制它的实例化。此外,在框架实例化了一个新创建的C之后,我无法轻松访问它。下面是C的外观: public class C implements I { public C() { // this ctor is invoked by the framework so can't use DI here?

我是Guice的新手,所以希望这不是一个明显的问题

我正在处理一个框架,它使用反射动态实例化我的一个应用程序类(我们称之为
C
),因此我无法控制它的实例化。此外,在框架实例化了一个新创建的
C
之后,我无法轻松访问它。下面是
C
的外观:

public class C implements I { public C() { // this ctor is invoked by the framework so can't use DI here? } public void initialize() { // this is a post instantiation hook which the f/w will invoke } private void m() { Dependency d = Dependency.getInstance(); d.doSmth(); } } 公共类C实现I{ 公共C(){ //这个ctor是由框架调用的,所以不能在这里使用DI? } 公共无效初始化(){ //这是f/w将调用的后实例化挂钩 } 私有无效m(){ Dependency d=Dependency.getInstance(); d、 doSmth(); } } 我希望
C
使用DI获取
依赖关系。在这里,
依赖关系
显然是一个单例,但通常情况下不必如此

我已经提出了两种可能的解决方案,这两种方案感觉都不整洁,所以我想我应该问问专家:

  • 静态注入。我很难看出这是如何在服务定位器反模式的基础上大幅改进的-我最终得到了可以在外部操纵的非最终静态字段。。。嗯

  • 框架支持一个钩子,用于
    C
    在实例化后初始化自身(上面显示的
    initialize()
    方法)。此方法可以使用setter注入自注入新创建的实例

  • 对于2,我想这意味着更多的外部可更改性,但对于单元测试之类的事情,至少会更明确地暴露依赖性。问题是:在这种情况下,我如何获得Guice注入器(除了依赖另一个服务定位器之外)?我也读过(并且倾向于同意)在整个应用程序代码中明确引用注入器是一种可疑的做法

    非常感谢你的洞察力

    非常感谢,

    Christian

    您可以尝试将提供程序静态注入到C中。静态注入更难测试。但是,提供程序使Guice能够急切地验证您的依赖项,而懒散地创建依赖项

    public class C implements I {
      @Inject static Provider<Dep1> dep1Provider;
      @Inject static Provider<Dep2> dep2Provider;
    
      ...
    
      public void initialize() {
        Dep1 dep1 = dep1Provider.get();
        Dep2 dep2 = dep2Provider.get();
        ...
      }
    }
    
    公共类C实现I{
    @注入静态提供者dep1Provider;
    @注入静态提供者dep2Provider;
    ...
    公共无效初始化(){
    Dep1 Dep1=dep1Provider.get();
    Dep2 Dep2=dep2Provider.get();
    ...
    }
    }
    
    如果您通过静态变量和静态访问器方法使Guice injector可用,您可以这样解决:

    public class C implements I {
    
        public C() {
            // this ctor is invoked by the framework, you can't do injection here.
        }        
    
        public void initialize() {
            MyGuice.getInjector().inject(this);
        }
    
        @Inject
        protected void init(Dep1 dep1, Dep2 dep2) {
            this.dep1 = dep1;
            this.dep2 = dep2;
        }
    
        private void m() {
            dept1.doSmth();
        }
    }
    
    静态调用有点反模式,如果您愿意使用代码编织或编译后步骤的解决方案,您可以通过一个简单的注释来消除这种依赖性,该注释负责后构造函数注入。这样,即使没有初始化方法,也可以注入所有对象。您可以在此处找到此示例:


    谢谢Jesse,这听起来与我上面的选项1相似;尽管我认为使用
    提供程序
    s确实使模式更通用。感谢Kdeveloper,这更像原始问题中列出的选项2,并提供了一个有用的高级技术演示,可用于缓解对全局状态的需要(即:第一个示例中的注入器)。我的直觉是,就代码的可维护性而言,补救措施(DI)开始感觉比疾病(服务定位器“反模式”)稍差一些,但有趣的是,与静态注入解决方案相比,结果代码的可测试性得到了改善。
    @Configurable
    public class C implements I {
    
        public C() {
            // this ctor is invoked by the framework, you can't do injection here.
        }        
    
        @Inject
        protected void init(Dep1 dep1, Dep2 dep2) {
            this.dep1 = dep1;
            this.dep2 = dep2;
        }
    
        private void m() {
            dept1.doSmth();
        }
    }