Spring通用存储库自动装配失败

时间:2018-12-12 17:33:58

标签: java spring spring-boot spring-data-jpa autowired

我有以下架构:

抽象控制器:

public abstract class AbstractController<E> {

    private final AbstractService<E> abstractService;

    public AbstractController(AbstractService<E> abstractService) {
        this.abstractService = abstractService;
    }

    @PostMapping("blabla")
    public List<Something> getList(@RequestBody whatever) {
        return abstractService.method(whatever);
    }

}

抽象服务:

public abstract class AbstractService<E> {

    @Autowired
    private SomeConcreteRepository concreteRepository;

    private final EntityTypeAwareRepository<E> entityRepository;

    @Autowired(required = false)
    public AbstractService(EntityTypeAwareRepository<E> entityRepository) {
        this.entityRepository = entityRepository;
    }


    List<Something> method() {
        String tableName = extractTableName(this.entityRepository.getEntityClass());
        return this.concreteRepository.someJdbcCall(tableName);
    }
}

实体A信息库:

@Repository
public interface EntityARepository extends EntityTypeAwareRepository<A>, JpaRepository<A, Long>, JdbcRepository {
    // JdbcRepository has implementation for A entity and its methods are called with EntityARepository in service layer
}

实体A控制器:

@RestController
@RequestMapping("base/mapping")
public class AController extends AbstractController<A> {

    private final AService aService;

    @Autowired
    public AController(AService aService) {
        super(aService);
        this.aService = aService;
    }

    // concrete endpoints methods
}

实体A服务:

@Service
@PreAuthorize(someRole)
@Transactional
public class AService extends AbstractService<A> {

    private final ARepository aRepository;

    @Autowired
    public AService(ARepository aRepository) {
        super(aRepository);
        this.aRepository = aRepository;
    }

    //methods using Spring-JPA aRepository methods
    //and 
    //methods using JdbcRepository interface implementation (via same reference)
}

它会根据您喜欢的任何实体进行缩放。 EntityTypeAwareRepositoryNoBeanRepository的defualt方法,用于查找具体的存储库实体。要点。抽象控制器正在从客户端获得针对不同种类实体的呼叫,但涉及同一件事。因此,目标是一个抽象控制器将处理对N个子控制器的调用。 SomeConcreteRepository是处理此逻辑的具体类。

问题在于它与抽象服务中的entityRepository一起无法自动装配。造成NPE。实际上,后者是从子控制器传递的,但解析为null。

实际上,在这种配置下,我可以通过某种方式使它工作,但是第二天,自动装配无法正常工作。因此,我不确定这种体系结构是否存在问题,或者我只是遇到了魔术般可行的建筑问题。您知道什么会引起问题吗?可以将其与@Transactional的代理连接吗?

我确信所有内容均已正确扫描,并且所有bean都可见。

1 个答案:

答案 0 :(得分:0)

在您的抽象控制器中,我将创建一个abstract AbstractService<E> getService()方法。然后在具体的控制器中,实现该吸气剂:

public abstract class AbstractController<E> {

    abstract AbstractService<E> getService();

    @GetMapping("/{id}")
    public E findById(Long id) {
        return getService().findById(id);
    }

    @PostMapping
    public E save(E entity) {
        return getService().save(entity);
    }
}

然后,具体的控制器如下所示:

@RestController
@RequestMapping("/a")
public AController extends AbstractController<A> {

    @AutoWired 
    AService service;

    public AbstractService<A> getService() {
        return service;
    }
}

该服务将使用abstract EntityRepository<E> getRepository()

实现相同的模式
public abstract class AbstractService<E> {

    public abstract EntityRepository<E> getRepository();

    public E findById(Long id) {
        return getRepository().findById(id);
    }

    public E save(E entity) {
        return getRepository().save(entity);
    }
}

具体服务如下:

@Service
public class AService extends AbstractService<A> {

    @Autowired
    ARepository repository;

    public EntityRepository<A> getRepository() {
        return repository;
    }
}

存储库是最后一层。 “抽象的”存储库如下所示:

@NoBeanRepository
public interface EntityRepository<E> extends EntityTypeAwareRepository<E>, JpaRepository<E, Long>, JdbcRepository {
    // Implementations are inherited... for findById(Long id), save(E entity), etc
}

然后我们使用“具体的”存储库对此进行扩展:

@Repository
public interface ARepository extends EntityRepository<A> {
}

我们得到如下信息:

enter image description here

这样,我们在“抽象”层没有用于服务或存储库的实例变量。我们只能通过抽象获取器访问具体版本。服务和存储库的具体实现是分别自动装配特定存储库和服务的实现的类。

我对此的原始答案是here