So erweitern Sie Spring mit Ihrem Repository-Typ am Beispiel von Infinispan

Warum darüber schreiben?

Dies ist mein erster Artikel, in dem ich versuchen werde, die praktischen Erfahrungen zu beschreiben, die ich mit dem Spring Repository unter der Haube des Frameworks gesammelt habe. Ich habe weder auf Russisch noch auf Englisch fertige Artikel zu diesem Thema im Internet gefunden, es gab nur wenige Quell-Repositories auf Github und den Quellcode von Spring selbst. Deshalb habe ich beschlossen, warum nicht schreiben, plötzlich ist das Thema des Schreibens eigener Repositorys für Spring für jemand anderen relevant.





Ich werde die Programmierung für Infinispan nicht im Detail betrachten. Die Implementierungsdetails finden Sie immer im Quellcode, der am Ende des Artikels angegeben ist. Das Hauptaugenmerk liegt auf der Paarung des Spring Boot Repository-Mechanismus und eines neuen Repository-Typs.





Wie alles begann

Während der Arbeit an einem der Projekte kam einer der Architekten auf die Idee, dass Sie Ihre eigenen Arten von Repositorys analog schreiben können, wie dies in verschiedenen Spring-Modulen (z. B. JPARepository, KeyValueRepository, CassandraRepository usw.) der Fall ist. Als Testimplementierung haben wir uns für die Arbeit mit Daten über Infinispan entschieden .





Natürlich sind Architekten vielbeschäftigte Leute, daher wurde der Java-Entwickler beauftragt, die Idee umzusetzen, d. H. mir.





Als ich anfing, im Internet an dem Thema zu arbeiten, gab Google hartnäckig fast einen Artikel darüber heraus, wie wunderbar es ist, JPARepository in allen Arten mit trivialen Beispielen zu verwenden. Es gab noch weniger Informationen zu KeyValueRepository. StackOverFlow hat traurige unbeantwortete Fragen zu einem ähnlichen Thema. Es gibt nichts zu tun, ich musste in die Quellen des Frühlings gehen.





Infinispan

Wenn wir kurz über Infinispan sprechen, dann ist dies nur ein verteilter Datenspeicher in Form eines Schlüsselwerts, und all dies wird ständig im Speicher zwischengespeichert. Wir überladen Infinispan, die Daten sind alle auf Null gesetzt.





, - 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- , , , .





Zusammenfassung

Nachdem wir nur 6 unserer Klassen geschrieben haben, haben wir einen neuen Repository-Typ erhalten, der mit Infinispan als Datenspeicher arbeiten kann. Und diese neue Art von Repository funktioniert sehr ähnlich wie Standard-Spring-Repositorys.





Das komplette Quell-Kit finden Sie auf meinem Github .





Spring Data KeyValue-Quellen können auch auf Github angezeigt werden .





Wenn Sie konstruktive Kommentare zu dieser Implementierung haben, schreiben Sie die Kommentare ein, oder Sie können im ursprünglichen Projekt eine Pull-Anfrage stellen.








All Articles