Cara memperpanjang Spring dengan tipe Repositori Anda menggunakan Infinispan sebagai contoh

Mengapa menulis tentang itu?

Ini adalah artikel pertama saya, di mana saya akan mencoba menjelaskan pengalaman praktis yang saya peroleh dengan Spring Repository di balik kerangka kerangka kerja. Saya tidak menemukan artikel siap pakai tentang topik ini di Internet baik dalam bahasa Rusia atau Inggris, hanya ada beberapa repositori sumber di github, dan kode sumber Spring itu sendiri. Oleh karena itu, saya memutuskan, mengapa tidak menulis, tiba-tiba topik menulis jenis repositori Anda sendiri untuk Spring relevan untuk orang lain.





Saya tidak akan mempertimbangkan pemrograman untuk Infinispan secara rinci, detail implementasi selalu dapat ditemukan dalam kode sumber yang ditentukan di akhir artikel. Penekanan utama ditempatkan pada pemasangan mekanisme Spring Boot Repository dan tipe repositori baru.





Bagaimana semua ini dimulai

Saat mengerjakan salah satu proyek, salah satu arsitek memiliki gagasan bahwa Anda dapat menulis jenis repositori Anda sendiri dengan analogi, seperti yang dilakukan di modul Spring yang berbeda (misalnya, JPARepository, KeyValueRepository, CassandraRepository, dll.). Sebagai implementasi uji coba, kami memutuskan untuk memilih bekerja dengan data melalui Infinispan .





Tentu arsitek adalah orang yang sibuk, sehingga pengembang Java ditugaskan untuk mengimplementasikan ide tersebut, yaitu. untuk saya.





Ketika saya mulai mengerjakan topik ini di Internet, Google dengan keras kepala memberikan hampir satu artikel tentang betapa indahnya menggunakan JPARepository dalam segala jenis dengan contoh-contoh yang sepele. Bahkan ada lebih sedikit informasi tentang KeyValueRepository. StackOverFlow memiliki pertanyaan sedih yang belum terjawab tentang topik serupa. Tidak ada yang bisa dilakukan, saya harus pergi ke sumber Spring.





Infinispan

Jika kita berbicara secara singkat tentang Infinispan, maka ini hanyalah penyimpanan data terdistribusi dalam bentuk nilai-kunci, dan semua ini terus-menerus di-cache dalam memori. Kami membebani Infinispan, semua data di nol.





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





Ringkasan

Karena hanya menulis 6 kelas kami, kami mendapat jenis repositori baru yang dapat bekerja dengan Infinispan sebagai penyimpanan data. Dan jenis repositori baru ini bekerja sangat mirip dengan repositori Spring standar.





Kit sumber lengkap dapat ditemukan di github saya .





Sumber Nilai Kunci Data Musim Semi juga dapat dilihat di github .





Jika Anda memiliki komentar konstruktif tentang implementasi ini, tulis di komentar, atau Anda dapat membuat permintaan tarik di proyek asli.








All Articles