简体   繁体   English

如何在NoRepositoryBean的实现内部自动装配bean

[英]How to autowire beans inside the implementation of a NoRepositoryBean

Using Spring Boot / Spring Data, I added a custom functionnality to all my repositories. 使用Spring Boot / Spring Data,我向所有存储库添加了自定义功能。 This is a snipped of what I did : 这是我所做的摘要:

So I have my repository Interface : 所以我有我的存储库接口:

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

And its implementation 及其实现

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

and my config : 和我的配置:

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

My custom methods works correctly but I need to inject messageLocal 我的自定义方法可以正常工作,但是我需要注入messageLocal

Autowired don't work inside RepositoryBaseImpl (I think that is because it is not a bean) Autowired在RepositoryBaseImpl内不起作用(我认为这是因为它不是bean)

I cannot add @Repository on RepositoryBaseImpl because I use @NoRepositoryBean on its parent interface 我无法在RepositoryBaseImpl上添加@Repository,因为我在其父接口上使用了@NoRepositoryBean

So is there a way to inject messageLocale ? 那么有没有办法注入messageLocale?

Based on @Prabhakar D comment, I will post my answer based on my need (using @EnableJpaRepositories besides @EnableMongoRepositories and some other little modifications) 基于@Prabhakar D评论,我将根据需要发布答案(使用@EnableJpaRepositories以及@EnableMongoRepositories和其他一些小修改)

In the @EnableJpaRepositories annotation, add the repositoryFactoryBeanClass : 在@EnableJpaRepositories批注中,添加repositoryFactoryBeanClass:

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

The key thing that is you can use @Autowire inside a repositoryFactoryBeanClass 关键是可以在repositoryFactoryBeanClass内部使用@Autowire

Create a repositoryFactoryBeanClass and autowire your beans in it. 创建一个repositoryFactoryBeanClass并在其中自动装配Bean。 This is a spring bean that create a custom JpaRepositoryFactory in the overrided method createRepositoryFactory : 这是一个Spring bean,它在覆盖的方法createRepositoryFactory中创建一个自定义JpaRepositoryFactory:

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

Now, create the custom factory (MyJpaRepositoryFactory) and use the overrided method getTargetRepository to create an instance of your base repository (RepositoryBaseImpl). 现在,创建自定义工厂(MyJpaRepositoryFactory)并使用重写的方法getTargetRepository创建基础存储库(RepositoryBaseImpl)的实例。 Here you can inject your bean in its constructor : 在这里,您可以将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 ******************** 
}

Now, just modify the constructer of your RepositoryBaseImpl so it can accept the required Bean : 现在,只需修改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

Now that your messageLocal is injected in your BaseRepositoryImpl, you can use it in your custom methods without having to pass it in parameters 现在,您的messageLocal已注入BaseRepositoryImpl中,您可以在自定义方法中使用它,而不必在参数中传递它

Hope that this will help someone 希望这会帮助某人

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

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