Spring:具有自动连接依赖项的泛型类

qnakjoqk  于 2022-10-30  发布在  Spring
关注(0)|答案(2)|浏览(114)

我有一个标准的Sping Boot MVC应用程序,它有许多实体和相应的存储库和服务。组件之间有很多共享的基础结构,所以我想将其抽象为泛型类。我目前尝试实现的方法是这样的(只展示了框架来传达这个想法):

interface AbstractRepository<T> {
    fun findById(entityId: Long): T 
}

abstract class AbstractEntityService<T>(
  private val entityRepository: AbstractRepository<T>,
) {

  fun getEntity(entityId: Long): T = entityRepository.findById(entityId)
}

@Repository
interface MyRepository : AbstractRepository<MyEntity>

@Service
class MyEntityService(
  myRepository: MyRepository,
  /* some other dependencies */
) : AbstractEntityService<MyEntity>(myRepository) {
  /* some additional methods */
}

这似乎是可行的,也就是说,我可以示例化(或自动连接)MyEntityService。但是,请注意,我必须显式地将MyRepository传递给构造函数,而不是让Spring自动连接它。这是不可能的,因为运行时类型擦除。但到目前为止,这并没有给我带来太大的困扰。
当我想向AbstractEntityService添加一些逻辑时,问题就出现了,这需要一些其他的bean,例如

@Service
abstract class AbstractEntityService<T>(
  private val entityRepository: AbstractRepository<T>,
) {

  @Autowired
  private lateinit var otherService: OtherService

  fun getEntity(entityId: Long): T

  fun commonMethodUsingOtherService(): T
}

但是现在我遇到了一个问题,因为为了自动连接OtherService,我必须使我的抽象服务成为一个Spring组件(@Service),这有一个不希望的副作用,即Spring试图注入在我的构造函数中声明的AbstractRepository<T>

我的问题:如何说服Spring不要将bean注入到AbstractEntityService构造函数中?
相关问题:对于我的问题(在第一段中提到的),是否有一个技术上不同的解决方案,可以避免可能的框架限制/缺点?即不使用继承,以不同的方式构建代码等。

raogr8fs

raogr8fs1#

通过用构造函数注入替换AbstractEntityService的字段注入,并删除@Service注解,可以很容易地解决这个问题:

abstract class AbstractEntityService<T>(
    private val entityRepository: AbstractRepository<T>,
    private val otherService: OtherService,
) {
    ...
}

现在,如果这个类不是抽象的,它的依赖关系可以被Spring注入,至少和otherService是一个字段的定义一样好。但是这个定义更好,因为你现在也可以把依赖关系从你的子类传递到这个类,如下所示:

@Service
class MyEntityService(
    myRepository: MyRepository,
    otherService: OtherService,
    /* some other dependencies */
) : AbstractEntityService<MyEntity>(myRepository, otherService) {
    /* some additional methods */
}

我不太清楚你的意思,为什么MyRepository不能自动连线,因为类型擦除,我猜有一些细节在问题中失踪。
如果问题是在应用程序上下文中有不同的MyRepository类型组件,则可以使用@Primary注解其中一个组件,这使得Spring在必须自动连接单个候选组件时选择该组件。
另一种方法是给予bean命名,然后在MyEntityService中限定依赖关系:

@Repository("myrepo")
open class MyRepository : AbstractRepository<MyEntity> {
   ...
}

@Service
class MyEntityService(
    @Qualifier("myrepo")
    myRepository: AbstractRepository<MyEntity>,
    otherService: OtherService,
    /* some other dependencies */
) : AbstractEntityService<MyEntity>(myRepository, otherService) {
    /* some additional methods */
}
xzlaal3s

xzlaal3s2#

原来,这

@Service
abstract class AbstractEntityService<T>(
  private val entityRepository: AbstractRepository<T>,
) {

  @Autowired
  private lateinit var otherService: OtherService

  fun getEntity(entityId: Long): T

  fun commonMethodUsingOtherService(): T
}

实际上是有效的,尽管OP(me)在问题中声明了什么。显然,Spring支持抽象类中的自动装配。此外,可以理解的是,Spring忽略了@Service注解(或通常的@Component),因此它不会尝试将AbstractRepository<T>注入到构造函数中。另一方面,如果显式声明,Spring可以注入它,因为它支持泛型作为bean限定符:

abstract class AbstractEntityService<T> {

  @Autowired
  private lateinit var otherService: OtherService

  @Autowired
  private lateinit var entityRepository: AbstractRepository<T>
}

我真的不知道当我发布这个问题时我在想什么:-)也许,我被IDE发出的错误弄糊涂了,IDE显然不是那么聪明,不能执行泛型类型bean解析,所以它抱怨Could not autowire. No beans of 'AbstractRepository<T>' type found.

相关问题