Как автоматически связывать бины внутри реализации NoRepositoryBean - PullRequest
0 голосов
/ 09 февраля 2019

Используя Spring Boot / Spring Data, я добавил пользовательский функционал во все свои репозитории.Это отрывок из того, что я сделал:

Итак, у меня есть мой интерфейс репозитория:

@NoRepositoryBean
public interface RepositoryBase<T, ID extends Serializable> extends JpaRepository<T, ID> {

И его реализация

public class RepositoryBaseImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements RepositoryBase<T, ID> {

    @Autowired 
    MessageLocale messageLocale; // <- this is a classic spring bean which is not injected in this spot (always null)

    private EntityManager entityManager;

    public RepositoryBaseImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }

    //... My custom methods here

и моя конфигурация:

@Configuration
@EnableJpaRepositories(basePackages = "my.base.pkg", repositoryBaseClass = RepositoryBaseImpl.class)
public class RepositoryConfig {
}

Мои пользовательские методы работают правильно, но мне нужно ввести messageLocal

Автопроводка не работает внутри RepositoryBaseImpl (я думаю, это потому, что это не бин)

Я не могудобавьте @Repository в RepositoryBaseImpl, потому что я использую @NoRepositoryBean в его родительском интерфейсе

Так есть ли способ внедрить messageLocale?

1 Ответ

0 голосов
/ 18 февраля 2019

Основываясь на комментарии @Prabhakar D, я опубликую свой ответ, основываясь на своих нуждах (используя @EnableJpaRepositories, кроме @EnableMongoRepositories и некоторых других небольших модификаций)

В аннотации @EnableJpaRepositories добавьте repositoryFactoryBeanClass:

@EnableJpaRepositories(basePackages = "my.base.pkg", repositoryBaseClass = RepositoryBaseImpl.class, repositoryFactoryBeanClass = MyRepositoryFactoryBean.class)

Ключевым моментом является то, что вы можете использовать @Autowire внутри репозиторияFactoryBeanClass

Создать репозиторийFactoryBeanClass и автоматически подключать к нему компоненты.Это пружинный компонент, создающий пользовательский JpaRepositoryFactory в переопределенном методе createRepositoryFactory:

public class MyRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {

    @Autowired
    private MessageLocale messageLocale;

    public MyRepositoryFactoryBean(Class repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new MyJpaRepositoryFactory(entityManager, messageLocale);
    }
}

Теперь создайте настраиваемую фабрику (MyJpaRepositoryFactory) и используйте переопределенный метод getTargetRepository для создания экземпляра базового репозитория (RepositoryBaseImpl).).Здесь вы можете вставить ваш bean-компонент в его конструктор:

public class MyJpaRepositoryFactory extends JpaRepositoryFactory {

    private EntityManager entityManager;
    private MessageLocale messageLocale;

    public MyJpaRepositoryFactory(EntityManager entityManager, MessageLocale messageLocale) {
        super(entityManager);
        this.entityManager = entityManager;
        this.messageLocale = messageLocale;
    }

    //****************** Edit ********************
    //starting from spring boot 2.1.0, getTargetRepository(RepositoryInformation information) was made final. So you can't override it anymore. You will need to override getTargetRepository(RepositoryInformation information, EntityManager entityManager)
    //@Override
    //protected Object getTargetRepository(RepositoryInformation information) {
    //    return new RepositoryBaseImpl(getEntityInformation(information.getDomainType()), entityManager, messageLocale);
    //}
    @Override
    protected JpaRepositoryImplementation<?, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager) {
        return new RepositoryBaseImpl(getEntityInformation(information.getDomainType()), entityManager, messageLocale);
    }
    //****************** End Edit ******************** 
}

Теперь просто измените конструктор вашего RepositoryBaseImpl, чтобы он мог принять требуемый Bean-компонент:

public class RepositoryBaseImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements RepositoryBase<T, ID> {

    private MessageLocale messageLocale;
    private EntityManager entityManager;

    //if you are using IntelliJ, it can show you an error saying "Could not autowire. No beans of JpaEntityInformation". It is just a bug in IntelliJ
    public RepositoryBaseImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager, MessageLocale messageLocale) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
        this.messageLocale = messageLocale;
    }

    //... My custom methods here

Теперь, когда ваш messageLocalвведенный в ваш BaseRepositoryImpl, вы можете использовать его в своих пользовательских методах без необходимости передавать его в параметрах

Надеюсь, что это кому-то поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...