如何在自定义Spring Data JPA存储库中注入配置

时间:2017-08-02 13:42:39

标签: java spring repository spring-data-jpa

我想基于JPA batch inserts with Hibernate & Spring Data中的代码向我的应用程序中的所有Spring Data JPA存储库添加自定义批量保存方法。 Spring Data doc explains how this can be done具有自定义存储库基类,如下所示。我的问题是如何在下面的示例中设置batchSize属性。使用@Value注入如下所示不起作用。

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

  void bulkSave(Iterable<T> entities);
}

public class BulkRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BulkRepository<T, ID> {

  private final EntityManager entityManager;

  @Value("${spring.jpa.properties.hibernate.jdbc.batch_size}")
  private int batchSize;

  public BulkRepositoryImpl(JpaEntityInformation entityInformation,
                          EntityManager entityManager) {
    super(entityInformation, entityManager);   
     this.entityManager = entityManager;
  }

  public void bulkSave(Iterable<T> entities) {
    // implementation using batchSize goes here
  }
}

我是否必须使用自定义JpaRepositoryFactoryBean来构建已配置的BulkRepositoryImpl?或者有更直接的方式吗?

2 个答案:

答案 0 :(得分:1)

我遇到了完全相同的问题,无法找到定义我自己的JpaRepositoryFactoryBean课程的方法。似乎自定义存储库基类的依赖关系不会像它们在标准bean中那样自动注入(请参阅herehere)。此外,在创建存储库接口的实例时,默认JpaRepositoryFactory仅将JpaEntityInformationEntityManager的实例传递给类构造函数(请参阅here)。据我所知,这有效地阻止了您为扩展SimpleJpaRepository的类添加其他依赖项。

我最终以下列方式定义了自定义工厂:

@Configuration
@ConfigurationProperties(prefix = "spring.jpa.properties.hibernate.jdbc")
public class RepositoryConfiguration {
    private int batchSize;
}

public class MyCustomRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {

    private RepositoryConfiguration repositoryConfiguration;

    public MyCustomRepositoryFactoryBean(Class<? extends R> repositoryInterface, RepositoryConfiguration repositoryConfiguration) {
        super(repositoryInterface);
        this.repositoryConfiguration = repositoryConfiguration;
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new MyCustomRepositoryFactory(entityManager, repositoryConfiguration);
    }

    private static class MyCustomRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {

        private RepositoryConfiguration repositoryConfiguration;

        MyCustomRepositoryFactory(EntityManager entityManager, RepositoryConfiguration repositoryConfiguration) {
            super(entityManager);
            this.repositoryConfiguration = repositoryConfiguration;
        }

        @Override
        @SuppressWarnings("unchecked")
        protected SimpleJpaRepository<?, ?> getTargetRepository(RepositoryInformation information, 
                EntityManager entityManager) {

            JpaEntityInformation<T, ?> entityInformation = 
                    (JpaEntityInformation<T, ?>) getEntityInformation(information.getDomainType());

            return new MyCustomRepositoryImpl<T, I>(
                    entityInformation, 
                    entityManager, 
                    repositoryConfiguration);
        }

        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return MyCustomRepositoryImpl.class;
        }
    }
}

虽然无法在@Value中注入MyCustomRepositoryFactoryBean的字段,但Spring会解析传递给构造函数的依赖项,因此您只需通过bean提供属性(RepositoryConfiguration在上面的代码中)并将其传递给MyCustomRepositoryImpl。最后,您需要通过添加

来指示Spring Data在创建存储库时使用您的FactoryBean
@EnableJpaRepositories(
        repositoryFactoryBeanClass = MyCustomRepositoryFactoryBean.class
)

@Configuration带注释的bean。这是很多样板,但它确实有效。

N.B。我正在使用spring-data-jpa:1.11.8.RELEASE

答案 1 :(得分:0)

您可以从EntityManager获取它。

var endpointAddress =
            new EndpointAddress("https://test/adfs/services/trust/13/usernamemixed");
        var binding = new Binding();
        var endpointReference = new EndpointReference("test");
        WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(binding, endpointAddress);
        trustChannelFactory.Credentials.UserName.UserName = "test";
        trustChannelFactory.Credentials.UserName.Password = "test";

        WSTrustChannel channel = (WSTrustChannel)trustChannelFactory.CreateChannel();

        var rst = new RequestSecurityToken
        {
            RequestType = RequestTypes.Issue,
            AppliesTo = endpointReference,
            KeyType = KeyTypes.Bearer
        };

        RequestSecurityTokenResponse rstr = null;
        try
        {
            SecurityToken token = channel.Issue(rst, out rstr);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }