我们的软件具有适用于所有功能的特定行为,在大多数情况下,操作中使用的实体发生了变化,为此,我们需要对@Repository层进行特定的实现。
因此,我们开发了具有一些泛型的“简单”架构@RestController
-> @Service
-> @Repository
,以使用所有功能。像这样:
@RestController
@RequestMapping("test")
// This is specific implementation
public class DiariasApi implements DefaultApiInterface<DiariasDTO, DiariasDTOFilter, Integer> {
@Autowired
private DefaultService<DiariasDTO, DiariasDTOFilter, Integer> defaultService;
@Override
@GetMapping("/page")
public Page<DiariasDTO> pageSearch(final DiariasDTOFilter filter) {
return this.defaultService.pageSearch(filter);
}
@Override
@GetMapping("/detail")
public DiariasDTO detail(@PathVariable("key") final Integer key) {
return this.defaultService.detail(key);
}
}
@Service
// This is generic implementation
public class DefaultService<D extends Serializable, F extends Serializable, C> {
@Autowired
// The Problem is here.
// Here I want the call to be the specific @Repository.
private DefaultRepositoryInterface<D, F, C> defaultRepository;
@Transactional(readOnly = true)
public Page<D> pageSearch(final F filter) {
return this.defaultRepository.pageSearch(filter);
}
@Transactional(readOnly = true)
public D detail(final C key) {
return this.defaultRepository.detail(key);
}
}
@Repository
// This is specific implementation
public class DiariasRepository implements DefaultRepositoryInterface<DiariasDTO, DiariasDTOFilter, Integer> {
@Override
public Page<DiariasDTO> pageSearch(final DiariasFiltro filtro) {
//some specific code;
}
@Override
public Optional<DiariasDTO> detail(final Integer key) {
//some specific code;
}
我们只想为每种功能实现@RestController
和@Repository
,并且让@Service
层只是一个知道如何调用特定{{1}的通用bean。 }。但是当我们这样做并且有多个实现时,我们会收到以下错误消息,该错误消息告诉我们@Repository
的问题:
@Autowired
我们希望Description:
Field defaultRepository in package.DefaultService required a single bean, but 2 were found:
- conveniosRepository: defined in file ...
- diariasRepository: defined in file ...
层是唯一的,我们能做到吗?
答案 0 :(得分:1)
您需要使用@Qualifier
来绑定特定的bean实例
@Service
// This is generic implementation
public class DefaultService<D extends Serializable, F extends Serializable, C> {
@Autowired
// The Problem is here.
// Here I want the call to be the specific @Repository.
@Qualifier("YourBeanId")
private DefaultRepositoryInterface<D, F, C> defaultRepository;
编辑
所以您可以使用我过去在本地v / s测试环境中使用过的另一种方法
类似于工厂的类,它将在运行时返回Bean的特定实例
创建Factory类
@Component
public class RepositoryFactoryImpl implements RepositoryFactory{
@Autowired
private DefaultRepositoryInterface conveniosRepository;
@Autowired
private DefaultRepositoryInterface diariasRepository;
@Override
public DefaultRepositoryInterface getInstance() {
if (some condition) {
return conveniosRepository;
}
if (some condition) {
return diariasRepository;
}
return null;
}
}
然后在您的DefaultService
@Service
// This is generic implementation
public class DefaultService<D extends Serializable, F extends Serializable, C> {
@Autowired
private RepositoryFactory factory;
@Transactional(readOnly = true)
public Page<D> pageSearch(final F filter) {
return this.factory.getInstance().pageSearch(filter);
}
@Transactional(readOnly = true)
public D detail(final C key) {
return this.factory.getInstance().detail(key);
}
}
答案 1 :(得分:0)
我认为您的方法非常好,我也有类似的方法。
您的问题-我认为是,您希望通用服务访问特定的存储库。制作一个扩展DiariasService
的{{1}},并让Spring自动连线到
Service<DiariasDto, DiariasFilter, Integer>
在构造器中扩展了DiariasRepository
,并将其传递给抽象服务。
您有一个新的但几乎是空的服务,但已正确解决了模棱两可的依赖关系。
我的Java不是最新鲜的,所以在Kotlin中,它看起来像:
Repository<DiariasDto, DiariasFilter, Integer>
我对abstract class Service<R : Resource, M : Model>(
protected open val factory: Factory<R, M>,
//...
)
class FooService(
factory: FooFactory, //spring bean type magic happens here and @Qualifier is applicable!
//...
) : Service<FooResource, FooModel>(
factory, //from one constuctor to the superclass constructor
//...
)
abstract class Factory<R : Resource, M : Model>(
//...
)
class FooFactory(
//...
) : Factory<FooResource, FooModel>(
//...
)
/ Controller
和FooController
/ Repository
使用相同的模式,依此类推。
当然有抽象的FooRepository
和Model
/ Resource
。
您不能在抽象的Entity
/ @Qualifier
/ Service
/ Controller
中使用Repository
,但要在具体的类中使用!