【问题标题】:How to inject specific dependency using constructor injection in an abstract class?如何在抽象类中使用构造函数注入来注入特定依赖项?
【发布时间】:2020-10-04 14:59:53
【问题描述】:

我有一个abstract 类,它具有以下构造函数 -

abstract class AbstractA<T> {
    protected CrudRepository<T, Long> crudRepository;  
    AbstractA(CrudRepository crudRepository) {
        this.crudRepository = crudRepository;
    }
}

abstract class AbstractB extend AbstractA<TableB> {
    protected Service service;
    // I want to autowire ConcreteCrudReposity here, but get myService from  
    //  subclass which is not a spring service.
    @Autowired 
    AbstractB(
        ConcreteCrudRepository<TableB, Long> concreteCrudRepository,
        MyService myService) {
        super(concreteCrudRepository);
    } 
}
class  AB extend AbstractB {
    AB() {
        super(new MyService()); // I know this is lame
    }
}

我想使用构造函数注入在抽象类 AbstractB 中注入一个 spring 服务,但另一个服务 (MyService) 需要来自不是 spring 服务的子类。

我知道我可以 @Autowire 子类中的依赖项,但可以在 AbstractB 中执行此操作,因为此依赖项实际上应该从 AbstractB 注入(请参阅通用实体类型)。而且我只有构造函数注入作为选项。请注意,我使用的是泛型,还有更多代码我没有展示以保持问题简单。

【问题讨论】:

  • 就像使用普通的 java 一样,您根本无法做到这一点。您需要通过调用 super 将所有依赖项传递给构造函数。否则将无法正常工作。

标签: java spring dependency-injection


【解决方案1】:

您可以自动装配到具体类,并使用参数调用超级构造函数

    @Component
    class  AB extend AbstractB {
    @Autowired 
         AB(ConcreteCrudRepository concreteCrudRepository) {
            super(concreteCrudRepository, new MyService()); // I know this is lame
        }
    }

【讨论】:

  • 没错,但问题是ConcreteCrudRepository确实属于AbstractB,并且有很多像AB这样的子类,我不想从所有子类中注入spring依赖。
【解决方案2】:

一个小技巧是在超级 class 中使用 field-injection

abstract class AbstractA {
    @Autowired
    protected CrudRepository crudRepository; 
}

或者setter-injection,更简洁,更容易测试:

abstract class AbstractA {
    protected CrudRepository crudRepository;

    @Autowired
    protected void setCrudRepository(CrudRepository crudRepository) {
        this.crudRepository = crudRepository;
    }
}

据我所知,这可以应用于层次结构中尽可能多的类。

【讨论】:

    【解决方案3】:

    如编译器所说,在 java 中你必须提供一个“匹配超级”的构造函数。不用管 spring,如果你不在 java 中做 - 它甚至不会编译。

    因此,假设您在问题中定义了带有构造函数的抽象类,那么您别无选择,只能像这样定义具体类:

     @Component
        class  AB extend AbstractB {
             @Autowired // putting autowired is not mandatory, btw as long as you have a single constructor in descent spring versions
             AB(ConcreteCrudRepository concreteCrudRepository, Service service) {
                super(concreteCrudRepository, service);
            }
        }
    

    在构造函数中使用new 分配服务将从java 的角度工作(将编译并运行),但您自己说过它应该由spring 管理,显然当您像这样使用new , spring 将对此服务一无所知,例如,如果MyService 有自己的依赖项,它们将不会被注入。

    让我也参考一下你的评论:

    问题是ConcreteCrudRepository确实属于AbstractB

    您基本上使用具体类AB 而不是使用抽象类- 在Java 中您根本无法实例化抽象类。这个AB 维护状态:服务和存储库。确实,从技术上讲,它是以“借用”超类代码的方式编写的,但我建议您认为您使用的是“独立”类。

    最后一点是关于像AB这样的无数类:

    只要 spring 管理所有这些(子类如AB、Service 和存储库),这应该不是问题:

    Spring 应该“足够聪明”来解决这样的依赖关系并注入任何需要的东西,只要它再次管理所有这些子类:注入的“魔力”只能发生在由弹簧本身。

    确实,如果您需要在 spring 中添加关于究竟应该注入什么的“提示”,您可以使用像 @Qualifier 这样的技术,但它已经是另一回事了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-30
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 2019-04-20
      • 2015-08-05
      相关资源
      最近更新 更多