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.