Как автоматически связать bean-компоненты внутри реализации NoRepositoryBean

Используя 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

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

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

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
1
1 145
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

В аннотацию @EnableJpaRepositories добавьте репозиторийFactoryBeanClass:

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

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

Создайте репозиторийFactoryBeanClass и автоматически подключите в нем свои компоненты. Это Spring bean, который создает пользовательский 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, вы можете использовать его в своих пользовательских методах без необходимости передавать его в параметрах.

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

Другие вопросы по теме