例としてInfinispanを使用してリポジトリタイプでSpringを拡張する方法

なぜそれについて書くのですか?

これは私の最初の記事であり、フレームワークの内部でSpringRepositoryで得た実際の経験について説明しようと思います。このトピックに関する既製の記事は、ロシア語でも英語でもインターネット上で見つかりませんでした。githubにはソースリポジトリがわずかしかなく、Spring自体のソースコードもありませんでした。したがって、私は、なぜ書いてみませんか、突然、Spring用に独自のタイプのリポジトリを作成するというトピックが他の誰かに関連していると判断しました。





Infinispanのプログラミングについては詳しく説明しません。実装の詳細は、記事の最後に指定されているソースコードでいつでも確認できます。主な重点は、Spring BootRepositoryメカニズムと新しいタイプのリポジトリの組み合わせにあります。





すべてが始まった経緯

プロジェクトの1つに取り組んでいるときに、アーキテクトの1人は、さまざまなSpringモジュール(たとえば、JPARepository、KeyValueRepository、CassandraRepositoryなど)で行われるように、類推によって独自のタイプのリポジトリを作成できるという考えを持っていました。試行的な実装として、Infinispanを介したデータの操作を選択することにしました





当然、アーキテクトは忙しい人なので、Java開発者がアイデアを実装するように割り当てられました。私に。





私がインターネットでこのトピックに取り組み始めたとき、Googleは、JPARepositoryをあらゆる種類で使用することの素晴らしさについて、簡単な例を挙げて、ほぼ1つの記事を頑固に発表しました。KeyValueRepositoryに関する情報はさらに少なかった。StackOverFlowには、同様のトピックに関する悲しい未回答の質問があります。何もすることはありません、私は春の情報源に行かなければなりませんでした。





インフィニスパン

Infinispanについて簡単に説明すると、これはキー値の形式の分散データストレージであり、これらすべてが常にメモリにキャッシュされます。Infinispanをオーバーロードすると、データはすべてゼロになります。





, - KeyValueRepository, , Spring. , Infinispan ( Hazelcast, ), , KeyValueRepository ConcurrentHashMap.





Spring - EnableMapRepositories.





@SpringBootApplication
@EnableMapRepositories("my.person.package.for.entities")
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

}
      
      



EnableInfinispanRepositories.





, , map infinispan, , .





EnableInfinispanRepositories
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(InfinispanRepositoriesRegistrar.class)
public @interface EnableInfinispanRepositories {

  String[] value() default {};

  String[] basePackages() default {};

  Class<?>[] basePackageClasses() default {};

  ComponentScan.Filter[] excludeFilters() default {};

  ComponentScan.Filter[] includeFilters() default {};

  String repositoryImplementationPostfix() default "Impl";

  String namedQueriesLocation() default "";

  QueryLookupStrategy.Key queryLookupStrategy() default 
    QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND;

  Class<?> repositoryFactoryBeanClass() default 
    KeyValueRepositoryFactoryBean.class;

  Class<?> repositoryBaseClass() default 
    DefaultRepositoryBaseClass.class;

  String keyValueTemplateRef() default "infinispanKeyValueTemplate";

  boolean considerNestedRepositories() default false;

}
      
      







EnableMapRepositories, , , .





@Import(MapRepositoriesRegistrar.class)
public @interface EnableMapRepositories {
}
      
      



MapRepositoriesRegistar.





public class MapRepositoriesRegistrar extends 
  RepositoryBeanDefinitionRegistrarSupport {

  @Override
  protected Class<? extends Annotation> getAnnotation() {
    return EnableMapRepositories.class;
  }
  
  @Override
  protected RepositoryConfigurationExtension getExtension() {
    return new MapRepositoryConfigurationExtension();
  }
}
      
      



. Registar , . , .





InfinispaRepositoriesRegistar.
@NoArgsConstructor
public class InfinispanRepositoriesRegistrar extends 
  RepositoryBeanDefinitionRegistrarSupport {

  @Override
  protected Class<? extends Annotation> getAnnotation() {
    return EnableInfinispanRepositories.class;
  }

  @Override
  protected RepositoryConfigurationExtension getExtension() {
    return new InfinispanRepositoryConfigurationExtension();
  }
}
      
      







, .





public class MapRepositoryConfigurationExtension extends 
  KeyValueRepositoryConfigurationExtension {

  @Override
  public String getModuleName() {
    return "Map";
  }

  @Override
  protected String getModulePrefix() {
    return "map";
  }

  @Override
  protected String getDefaultKeyValueTemplateRef() {
    return "mapKeyValueTemplate";
  }

  @Override
  protected AbstractBeanDefinition getDefaultKeyValueTemplateBeanDefinition(RepositoryConfigurationSource configurationSource) {
    BeanDefinitionBuilder adapterBuilder = BeanDefinitionBuilder
      .rootBeanDefinition(MapKeyValueAdapter.class);
    adapterBuilder.addConstructorArgValue(
      getMapTypeToUse(configurationSource));
    BeanDefinitionBuilder builder = BeanDefinitionBuilder
      .rootBeanDefinition(KeyValueTemplate.class);
    ...
  }
  ...
}
      
      



MapKeyValueAdapter , HashMap. KeyValueTemplate .





Infinispan, ConfigurationExtension, , // , Infinispan.





InfinispanRepositoriesConfigurationExtension
@NoArgsConstructor
public class InfinispanRepositoryConfigurationExtension 
  extends KeyValueRepositoryConfigurationExtension {

  @Override
  public String getModuleName() {
    return "Infinispan";
  }

  @Override
  protected String getModulePrefix() {
    return "infinispan";
  }

  @Override
  protected String getDefaultKeyValueTemplateRef() {
    return "infinispanKeyValueTemplate";
  }

  @Override
  protected Collection<Class<?>> getIdentifyingTypes() {
    return Collections.singleton(InfinispanRepository.class);
  }

  @Override
  protected AbstractBeanDefinition getDefaultKeyValueTemplateBeanDefinition(RepositoryConfigurationSource configurationSource) {
    RootBeanDefinition infinispanKeyValueAdapterDefinition = 
      new RootBeanDefinition(InfinispanKeyValueAdapter.class);
    RootBeanDefinition keyValueTemplateDefinition = 
      new RootBeanDefinition(KeyValueTemplate.class);
    ConstructorArgumentValues constructorArgumentValuesForKeyValueTemplate = new ConstructorArgumentValues();
    constructorArgumentValuesForKeyValueTemplate
      .addGenericArgumentValue(infinispanKeyValueAdapterDefinition);
    keyValueTemplateDefinition.setConstructorArgumentValues(
      constructorArgumentValuesForKeyValueTemplate);
    return keyValueTemplateDefinition;
  }
}
      
      







ConfigurationExtension getIdentifyingTypes(), (. ).





@NoRepositoryBean
public interface InfinispanRepository <T, ID> extends 
  PagingAndSortingRepository<T, ID> {
}
      
      



, KeyValueTemplate, .





@Configuration
public class InfinispanConfiguration extends CachingConfigurerSupport {

  @Autowired
  private ApplicationContext applicationContext;

  @Bean
  public InfinispanKeyValueAdapter getInfinispanAdapter() {
    return new InfinispanKeyValueAdapter(
      applicationContext.getBean(CacheManager.class)
    );
  }

  @Bean("infinispanKeyValueTemplate")
  public KeyValueTemplate getInfinispanKeyValueTemplate() {
    return new KeyValueTemplate(getInfinispanAdapter());
  }
}
      
      



.





, , Spring- , , , .





概要

クラスを6つだけ作成したので、Infinispanをデータストアとして使用できる新しいタイプのリポジトリを入手しました。そして、この新しいタイプのリポジトリは、標準のSpringリポジトリと非常によく似ています。





完全なソースキットは私のgithubにあります。





Spring DataKeyValueソースはgithubでも見ることができます。





この実装について建設的なコメントがある場合は、コメントを書き込むか、元のプロジェクトでプルリクエストを行うことができます。








All Articles