¿Por qué escribir sobre eso?
Este es mi primer artículo, en el que intentaré describir la experiencia práctica que obtuve con Spring Repository bajo el capó del marco. No encontré artículos listos para usar sobre este tema en Internet, ni en ruso ni en inglés, solo había unos pocos repositorios de fuentes en github y el código fuente de Spring. Por lo tanto, decidí, ¿por qué no escribir? De repente, el tema de escribir sus propios tipos de repositorios para Spring es relevante para otra persona.
No consideraré la programación para Infinispan en detalle, los detalles de implementación siempre se pueden ver en el código fuente especificado al final del artículo. El énfasis principal se coloca en el emparejamiento del mecanismo Spring Boot Repository y un nuevo tipo de repositorio.
Cómo todo empezó
Mientras trabajaba en uno de los proyectos, uno de los arquitectos tuvo la idea de que puedes escribir tus propios tipos de repositorios por analogía, como se hace en diferentes módulos de Spring (por ejemplo, JPARepository, KeyValueRepository, CassandraRepository, etc.). Como implementación de prueba, decidimos elegir trabajar con datos a través de Infinispan .
Naturalmente, los arquitectos son personas ocupadas, por lo que se asignó al desarrollador de Java para implementar la idea, es decir, a mi.
Cuando comencé a trabajar en el tema en Internet, Google obstinadamente dio casi un artículo sobre lo maravilloso que es usar JPARepository en todo tipo con ejemplos triviales. Incluso había menos información sobre KeyValueRepository. StackOverFlow tiene tristes preguntas sin respuesta sobre un tema similar. No hay nada que hacer, tuve que ir a las fuentes de Spring.
Infinispan
Si hablamos brevemente de Infinispan, entonces esto es solo un almacenamiento de datos distribuido en forma de valor clave, y todo esto se almacena constantemente en la memoria caché. Sobrecargamos Infinispan, todos los datos se ponen a cero.
, - 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- , , , .
Resumen
Habiendo escrito solo 6 de nuestras clases, obtuvimos un nuevo tipo de repositorio que puede funcionar con Infinispan como almacén de datos. Y este nuevo tipo de repositorio funciona de manera muy similar a los repositorios estándar de Spring.
El kit de fuentes completo se puede encontrar en mi github .
Las fuentes de Spring Data KeyValue también se pueden ver en github .
Si tiene comentarios constructivos sobre esta implementación, escriba los comentarios o puede realizar una solicitud de extracción en el proyecto original.