【问题标题】:Spring Boot: How to declare a custom repository factory beanSpring Boot:如何声明自定义存储库工厂 bean
【发布时间】:2016-08-11 19:42:53
【问题描述】:

我在应用程序上使用 Spring Boot (1.3.3) 和基于注释的/JavaConfig 配置。 我有以下存储库接口:

@RepositoryRestResource(collectionResourceRel = "something", path = "something")
public interface SomethingRepository 
    extends CrudRepository<SomethingRepository, Long> {

}

我想做的是覆盖生成的存储库代理中某些方法的行为。我发现这样做的唯一方法是基于文档建议添加新的自定义方法(请参阅:Adding custom behavior to single repositories),因此我定义了以下接口:

public interface SomethingRepositoryCustom {
    Something findOne(Long id);
}

...我添加了相应的实现:

public SomethingRepositoryImpl extends SimpleJpaRepository<Something, Long> 
    implements SomethingRepositoryCustom {

    public SomethingRepositoryImpl(<Something> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }

    @Override
    public Something findOne(Long id) {
        System.out.println("custom find one");
        // do whatever I want and then fetch the object
        return null;
    }

}

现在,如果我启动应用程序,我会收到以下错误:

... org.springframework.beans.BeanInstantiationException: 失败 实例化 [com.dummy.repositories.SomethingRepositoryImpl]:否 找到默认构造函数;嵌套异常是 java.lang.NoSuchMethodException: com.dummy.repositories.SomethingRepositoryImpl.() ...

问题: 如何解决 BeanInstantiationException?我假设我需要声明一个存储库工厂 bean,但我不确定如何覆盖 Spring Boot 配置。

【问题讨论】:

    标签: java spring spring-boot spring-data


    【解决方案1】:

    确实,您必须在 @EnableJpaRepositories 注释中声明一个新的 FactoryBean:

    @Configuration
    @EnableJpaRepositories(value = "your_package",
            repositoryFactoryBeanClass = CustomFactoryBean.class)
    public class ConfigurationClass{}
    

    CustomFactoryBean.java:

    public class CustomFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I>{
    
        @Override
        protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
            return new SimpleJpaExecutorFactory(entityManager);
        }
    
        /**
         * Simple jpa executor factory
         * @param <T>
         * @param <I>
         */
        private static class SimpleJpaExecutorFactory<T, I extends Serializable> extends JpaRepositoryFactory{
    
            private EntityManager entityManager;
    
            /**
             * Simple jpa executor factory constructor
             * @param entityManager entity manager
             */
            public SimpleJpaExecutorFactory(EntityManager entityManager) {
                super(entityManager);
                this.entityManager = entityManager;
            }
    
            @Override
            protected Object getTargetRepository(RepositoryMetadata metadata) {
                JpaEntityInformation entityInformation =
                        getEntityInformation(metadata.getDomainType());
                return new SomethingRepositoryImpl<T,I>(entityInformation, entityManager);
            }
    
            @Override
            protected Class getRepositoryBaseClass(RepositoryMetadata metadata) {
                return SomethingRepositoryImpl.class;
            }
        }
    }
    

    然后将使用您的SimpleJpaRepository 实例:SimpleJpaRepositoryImpl

    【讨论】:

    • 我试过了,但它仍在尝试实例化 SomethingRepositoryImpl 的默认构造函数。这是因为,按照惯例,Spring 会获取以 Impl 结尾的类名。我更改了 Impl 后缀并添加了您提供的代码并且它工作了。
    • 如果我需要自定义多个存储库,这种方法是否可行?看起来你只能在@EnableJpaRepositories 中定义一个repositoryFactoryBeanClass。
    • 是的,因为 repositoryFactoryBeanClass 允许您指向您的自定义 SimpleJpaRepository 实例,该实例将由您的所有存储库共享
    • OP 没有跟进,但我试了一下,效果符合建议。
    【解决方案2】:

    从 1.9 版开始,您不再需要创建新的 FactoryBean 类,而是可以直接设置基础存储库。来自Baeldung:

    @Configuration
    @EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao", 
      repositoryBaseClass = ExtendedRepositoryImpl.class)
    public class StudentJPAH2Config {
        // additional JPA Configuration
    }
    
    public class ExtendedRepositoryImpl<T, ID extends Serializable>
      extends SimpleJpaRepository<T, ID> implements ExtendedRepository<T, ID> {
        
        private EntityManager entityManager;
    
        public ExtendedRepositoryImpl(JpaEntityInformation<T, ?> 
          entityInformation, EntityManager entityManager) {
            super(entityInformation, entityManager);
            this.entityManager = entityManager;
        }
    
        // ...
    }
    

    【讨论】:

      猜你喜欢
      • 2018-05-07
      • 1970-01-01
      • 1970-01-01
      • 2015-08-17
      • 2019-04-03
      • 2017-12-03
      • 2021-06-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多