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.