Add AOT support for redis repositories.

We now use the AOT infrastructure of Spring Framework 6 and data commons to provide AOT support building the foundation for native image compilation.
Additionally we register hints for GraalVM native image.

See: #2350
This commit is contained in:
Christoph Strobl
2022-06-24 14:11:46 +02:00
parent 8c4052329f
commit 47c1ff54dd
3 changed files with 158 additions and 18 deletions

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.redis.aot;
import java.util.Arrays;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.lang.Nullable;
/**
* @author Christoph Strobl
* @since 3.0
*/
public class DataRedisRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
// REFLECTION
hints.reflection()
.registerTypes(
Arrays.asList(TypeReference.of(org.springframework.data.redis.connection.RedisConnection.class),
TypeReference.of(org.springframework.data.redis.connection.StringRedisConnection.class),
TypeReference.of(org.springframework.data.redis.connection.DefaultedRedisConnection.class),
TypeReference.of(org.springframework.data.redis.connection.DefaultedRedisClusterConnection.class),
TypeReference.of(org.springframework.data.redis.connection.RedisKeyCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisStringCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisListCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisSetCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisZSetCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisHashCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisTxCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisPubSubCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisConnectionCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisServerCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisStreamCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisScriptingCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisGeoCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisHyperLogLogCommands.class),
TypeReference.of(org.springframework.data.redis.connection.RedisClusterCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveRedisConnection.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveKeyCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveStringCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveListCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveSetCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveZSetCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveHashCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactivePubSubCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveServerCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveStreamCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveScriptingCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveGeoCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveHyperLogLogCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterKeyCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterStringCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterListCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterSetCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterZSetCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterHashCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterServerCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterStreamCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterScriptingCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterGeoCommands.class),
TypeReference.of(org.springframework.data.redis.connection.ReactiveClusterHyperLogLogCommands.class),
TypeReference.of(org.springframework.data.redis.core.ReactiveRedisOperations.class),
TypeReference.of(org.springframework.data.redis.core.ReactiveRedisTemplate.class),
TypeReference.of(org.springframework.data.redis.core.RedisOperations.class),
TypeReference.of(org.springframework.data.redis.core.RedisTemplate.class),
TypeReference.of(org.springframework.data.redis.core.StringRedisTemplate.class),
TypeReference.of(org.springframework.data.keyvalue.annotation.KeySpace.class),
TypeReference.of(org.springframework.data.keyvalue.core.AbstractKeyValueAdapter.class),
TypeReference.of(org.springframework.data.keyvalue.core.KeyValueAdapter.class),
TypeReference.of(org.springframework.data.keyvalue.core.KeyValueOperations.class),
TypeReference.of(org.springframework.data.keyvalue.core.KeyValueTemplate.class),
TypeReference.of(org.springframework.data.keyvalue.core.mapping.context.KeyValueMappingContext.class),
TypeReference.of(org.springframework.data.keyvalue.repository.KeyValueRepository.class),
TypeReference
.of(org.springframework.data.keyvalue.repository.support.KeyValueRepositoryFactoryBean.class),
TypeReference.of(org.springframework.data.keyvalue.repository.config.QueryCreatorType.class),
TypeReference.of(org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.class),
TypeReference.of(org.springframework.data.redis.core.RedisKeyValueAdapter.class),
TypeReference.of(org.springframework.data.redis.core.RedisKeyValueTemplate.class),
TypeReference.of(org.springframework.data.redis.core.convert.KeyspaceConfiguration.class),
TypeReference.of(org.springframework.data.redis.core.convert.MappingConfiguration.class),
TypeReference.of(org.springframework.data.redis.core.convert.MappingRedisConverter.class),
TypeReference.of(org.springframework.data.redis.core.convert.RedisConverter.class),
TypeReference.of(org.springframework.data.redis.core.convert.RedisCustomConversions.class),
TypeReference.of(org.springframework.data.redis.core.convert.ReferenceResolver.class),
TypeReference.of(org.springframework.data.redis.core.convert.ReferenceResolverImpl.class),
TypeReference.of(org.springframework.data.redis.core.index.IndexConfiguration.class),
TypeReference.of(org.springframework.data.redis.core.index.ConfigurableIndexDefinitionProvider.class),
TypeReference.of(org.springframework.data.redis.core.mapping.RedisMappingContext.class),
TypeReference.of(org.springframework.data.redis.repository.support.RedisRepositoryFactoryBean.class),
TypeReference.of(org.springframework.data.redis.repository.query.RedisQueryCreator.class)),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_PUBLIC_METHODS));
// PROXIES
hints.proxies().registerJdkProxy(TypeReference.of(org.springframework.data.redis.connection.RedisConnection.class));
hints.proxies()
.registerJdkProxy(TypeReference.of(org.springframework.data.redis.connection.DefaultedRedisConnection.class));
hints.proxies()
.registerJdkProxy(TypeReference.of(org.springframework.data.redis.connection.ReactiveRedisConnection.class));
hints.proxies().registerJdkProxy(
TypeReference.of(org.springframework.data.redis.connection.StringRedisConnection.class),
TypeReference.of(org.springframework.data.redis.connection.DecoratedRedisConnection.class));
}
}

View File

@@ -22,6 +22,7 @@ import java.util.Collections;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.data.keyvalue.repository.config.KeyValueRepositoryConfigurationExtension;
@@ -51,6 +52,7 @@ public class RedisRepositoryConfigurationExtension extends KeyValueRepositoryCon
private static final String REDIS_REFERENCE_RESOLVER_BEAN_NAME = "redisReferenceResolver";
private static final String REDIS_ADAPTER_BEAN_NAME = "redisKeyValueAdapter";
private static final String REDIS_CUSTOM_CONVERSIONS_BEAN_NAME = "redisCustomConversions";
private static final String REDIS_MAPPING_CONFIG_BEAN_NAME = "redisMappingConfiguration";
@Override
public String getModuleName() {
@@ -77,8 +79,29 @@ public class RedisRepositoryConfigurationExtension extends KeyValueRepositoryCon
"@EnableRedisRepositories(redisTemplateRef = … ) must be configured to a non empty value");
}
registerIfNotAlreadyRegistered(() -> createRedisMappingContext(configuration), registry, MAPPING_CONTEXT_BEAN_NAME,
configuration.getSource());
// Mapping config
String mappingConfigBeanName = BeanDefinitionReaderUtils.uniqueBeanName(REDIS_MAPPING_CONFIG_BEAN_NAME, registry);
String indexConfigurationBeanName = BeanDefinitionReaderUtils.uniqueBeanName("redisIndexConfiguration", registry);
String keyspaceConfigurationBeanName = BeanDefinitionReaderUtils.uniqueBeanName("redisKeyspaceConfiguration",
registry);
registerIfNotAlreadyRegistered(() -> BeanDefinitionBuilder
.rootBeanDefinition(configuration.getRequiredAttribute("indexConfiguration", Class.class)) //
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE) //
.getBeanDefinition(), registry, indexConfigurationBeanName, configuration.getSource());
registerIfNotAlreadyRegistered(() -> BeanDefinitionBuilder
.rootBeanDefinition(configuration.getRequiredAttribute("keyspaceConfiguration", Class.class)) //
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE) //
.getBeanDefinition(), registry, keyspaceConfigurationBeanName, configuration.getSource());
registerIfNotAlreadyRegistered(
() -> createMappingConfigBeanDef(indexConfigurationBeanName, keyspaceConfigurationBeanName), registry,
mappingConfigBeanName, configuration.getSource());
registerIfNotAlreadyRegistered(() -> createRedisMappingContext(mappingConfigBeanName), registry,
MAPPING_CONTEXT_BEAN_NAME, configuration.getSource());
// Register custom conversions
registerIfNotAlreadyRegistered(() -> new RootBeanDefinition(RedisCustomConversions.class), registry,
@@ -122,8 +145,7 @@ public class RedisRepositoryConfigurationExtension extends KeyValueRepositoryCon
configuration.getRequiredAttribute("enableKeyspaceEvents", EnableKeyspaceEvents.class)) //
.addPropertyValue("keyspaceNotificationsConfigParameter",
configuration.getAttribute("keyspaceNotificationsConfigParameter", String.class).orElse("")) //
.addPropertyValue("shadowCopy",
configuration.getRequiredAttribute("shadowCopy", ShadowCopy.class)) //
.addPropertyValue("shadowCopy", configuration.getRequiredAttribute("shadowCopy", ShadowCopy.class)) //
.getBeanDefinition();
}
@@ -134,26 +156,17 @@ public class RedisRepositoryConfigurationExtension extends KeyValueRepositoryCon
.getBeanDefinition();
}
private static AbstractBeanDefinition createRedisMappingContext(RepositoryConfigurationSource configurationSource) {
private static AbstractBeanDefinition createRedisMappingContext(String mappingConfigRef) {
return BeanDefinitionBuilder.rootBeanDefinition(RedisMappingContext.class) //
.addConstructorArgValue(createMappingConfigBeanDef(configurationSource)) //
.getBeanDefinition();
.addConstructorArgReference(mappingConfigRef).getBeanDefinition();
}
private static BeanDefinition createMappingConfigBeanDef(RepositoryConfigurationSource configuration) {
BeanDefinition indexDefinition = BeanDefinitionBuilder
.genericBeanDefinition(configuration.getRequiredAttribute("indexConfiguration", Class.class)) //
.getBeanDefinition();
BeanDefinition keyspaceDefinition = BeanDefinitionBuilder
.genericBeanDefinition(configuration.getRequiredAttribute("keyspaceConfiguration", Class.class)) //
.getBeanDefinition();
private static AbstractBeanDefinition createMappingConfigBeanDef(String indexConfigRef, String keyspaceConfigRef) {
return BeanDefinitionBuilder.genericBeanDefinition(MappingConfiguration.class) //
.addConstructorArgValue(indexDefinition) //
.addConstructorArgValue(keyspaceDefinition) //
.addConstructorArgReference(indexConfigRef) //
.addConstructorArgReference(keyspaceConfigRef) //
.getBeanDefinition();
}