Неисправность автоматической разметки пружинного хранилища - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть следующая архитектура:

Абстрактный контроллер:

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

И он масштабируется для любого объекта, который вам нравится.EntityTypeAwareRepository - это NoBeanRepository с методом defualt для поиска конкретного объекта хранилища.К точке.Абстрактный контроллер получает звонки от клиента для разных типов объектов, но относительно одной и той же вещи.Таким образом, цель состоит в том, чтобы один абстрактный контроллер обрабатывал вызовы для N субконтроллеров.SomeConcreteRepository - это конкретный класс, обрабатывающий эту логику.

Проблема в том, что это не автоматическое подключение, вместе с entityRepository в абстрактном сервисе.вызывая NPE.На самом деле последний передается из субконтроллера, но разрешается в ноль.

И фактически в этой конфигурации у меня это работало как-то, но на следующий день автопроводка не работала должным образом.Так что я не уверен, есть ли какая-то проблема с этой архитектурой, или у меня просто были некоторые проблемы со сборкой, которые волшебным образом работалиУ вас есть идея, что может вызвать проблемы?Может ли это быть связано с прокси от @Transactional?

Я уверен, что все правильно отсканировано и все компоненты видны.

1 Ответ

0 голосов
/ 12 декабря 2018

В вашем абстрактном контроллере я бы сделал метод 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;
    }
}

Хранилище является последним слоем.Репозиторий "abstract-ish" выглядит следующим образом:

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

Затем мы расширяем его с помощью репозитория "concrete-ish":

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

Мы получаем что-то вроде следующего:

enter image description here

Таким образом, у нас нет переменных экземпляра для службы или хранилища на «абстрактном» уровне.Мы можем получить доступ к конкретной версии только через абстрактные методы получения.Конкретные реализации сервисов и репозиториев являются единственными классами, которые автоматически связывают реализации конкретного репозитория и сервиса, соответственно.

Мой оригинальный ответ на этот вопрос здесь

...