我有一个标准的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
构造函数中?
相关问题:对于我的问题(在第一段中提到的),是否有一个技术上不同的解决方案,可以避免可能的框架限制/缺点?即不使用继承,以不同的方式构建代码等。
2条答案
按热度按时间raogr8fs1#
通过用构造函数注入替换
AbstractEntityService
的字段注入,并删除@Service
注解,可以很容易地解决这个问题:现在,如果这个类不是抽象的,它的依赖关系可以被Spring注入,至少和
otherService
是一个字段的定义一样好。但是这个定义更好,因为你现在也可以把依赖关系从你的子类传递到这个类,如下所示:我不太清楚你的意思,为什么
MyRepository
不能自动连线,因为类型擦除,我猜有一些细节在问题中失踪。如果问题是在应用程序上下文中有不同的
MyRepository
类型组件,则可以使用@Primary
注解其中一个组件,这使得Spring在必须自动连接单个候选组件时选择该组件。另一种方法是给予bean命名,然后在
MyEntityService
中限定依赖关系:xzlaal3s2#
原来,这
实际上是有效的,尽管OP(me)在问题中声明了什么。显然,Spring支持抽象类中的自动装配。此外,可以理解的是,Spring忽略了
@Service
注解(或通常的@Component
),因此它不会尝试将AbstractRepository<T>
注入到构造函数中。另一方面,如果显式声明,Spring可以注入它,因为它支持泛型作为bean限定符:我真的不知道当我发布这个问题时我在想什么:-)也许,我被IDE发出的错误弄糊涂了,IDE显然不是那么聪明,不能执行泛型类型bean解析,所以它抱怨
Could not autowire. No beans of 'AbstractRepository<T>' type found.