繁体   English   中英

如何创建注入特定@Repository的通用@Service?

[英]How to Create Generic @Service That Injects Specific @Repository?

我们的软件具有适用于所有功能的特定行为,在大多数情况下,操作中使用的Entity是什么变化,为此,我们需要@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层只有一个普通的豆腐,它知道如何调用特定的@Repository 但是,当我们这样做并且有多个实现时,我们会收到以下错误消息,该错误消息告诉我们@Autowired的问题:

Description:
Field defaultRepository in package.DefaultService required a single bean, but 2 were found:
    - conveniosRepository: defined in file ...
    - diariasRepository: defined in file ...

我们希望@Service层是唯一的,可以做到吗?

您需要使用@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的特定实例

创建一个工厂类

@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);
    }
 }

我认为您的方法很好,我也有类似的方法。 您的问题-我认为是,您希望通用服务访问特定的存储库。 做一个DiariasService延伸Service<DiariasDto, DiariasFilter, Integer>和让Spring自动装配在DiariasRepository扩展Repository<DiariasDto, DiariasFilter, Integer> 在constuctor并把它传递到抽象服务。

您有一个新的但几乎是空的服务,但已正确解决了模棱两可的依赖关系。

我的Java不是最新鲜的,所以在kotlin中,它看起来像:

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 / FooControllerRepository / FooRepository等使用相同的模式。

当然,有抽象的ModelResource / Entity

您不能在抽象的Service / Controller / Repository / Factory使用@Qualifier ,而是在具体的类中使用@Qualifier

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM