Compare commits

...

1 Commits

Author SHA1 Message Date
Olga Maciaszek-Sharma abff4043bf Add native hints for Caffeine cache. 2 years ago
  1. 2
      docs/src/main/asciidoc/spring-cloud-commons.adoc
  2. 61
      spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfiguration.java
  3. 2
      spring-cloud-loadbalancer/src/main/resources/META-INF/spring/aot.factories
  4. 1
      spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfigurationTests.java

2
docs/src/main/asciidoc/spring-cloud-commons.adoc

@ -635,7 +635,7 @@ public class MyClass {
The Spring WebFlux can work with both reactive and non-reactive `WebClient` configurations, as the topics describe: The Spring WebFlux can work with both reactive and non-reactive `WebClient` configurations, as the topics describe:
* <<webflux-with-reactive-loadbalancer>> * <<webflux-with-reactive-loadbalancer>>
* <<load-balancer-exchange-filter-functionload-balancer-exchange-filter-function>> * <<load-balancer-exchange-filter-function>>
[[webflux-with-reactive-loadbalancer]] [[webflux-with-reactive-loadbalancer]]
==== Spring WebFlux `WebClient` with `ReactorLoadBalancerExchangeFilterFunction` ==== Spring WebFlux `WebClient` with `ReactorLoadBalancerExchangeFilterFunction`

61
spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfiguration.java

@ -16,12 +16,21 @@
package org.springframework.cloud.loadbalancer.config; package org.springframework.cloud.loadbalancer.config;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.stoyanr.evictor.ConcurrentMapWithTimedEviction; import com.stoyanr.evictor.ConcurrentMapWithTimedEviction;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
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.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.AllNestedConditions; import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
@ -39,8 +48,11 @@ import org.springframework.cloud.loadbalancer.cache.DefaultLoadBalancerCacheMana
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager; import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheProperties; import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.ClassUtils;
/** /**
* An AutoConfiguration that automatically enables caching when Spring Boot, and Spring * An AutoConfiguration that automatically enables caching when Spring Boot, and Spring
@ -149,3 +161,52 @@ public class LoadBalancerCacheAutoConfiguration {
} }
} }
// Remove after adding hints to GraalVM reachability metadata repo
class CaffeineHints implements RuntimeHintsRegistrar {
private static final Log LOG = LogFactory.getLog(CaffeineHints.class);
private static final String CAFFEINE_BOUNDED_LOCAL_CACHE_CLASS_NAME = "com.github.benmanes.caffeine.cache.BoundedLocalCache";
private static final String CAFFEINE_CACHE_BASE_PACKAGE = "com/github/benmanes/caffeine/cache";
private static final String CAFFEINE_NODE_CLASS_NAME = "com.github.benmanes.caffeine.cache.Node";
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (!ClassUtils.isPresent("com.github.benmanes.caffeine.cache.Caffeine", classLoader)) {
return;
}
hints.reflection()
.registerType(TypeReference.of(Caffeine.class),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.registerType(TypeReference.of("com.github.benmanes.caffeine.cache.BoundedLocalCache"),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.registerType(TypeReference.of("com.github.benmanes.caffeine.cache.LocalCacheFactory"),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS))
.registerType(TypeReference.of("com.github.benmanes.caffeine.cache.Node"),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS));
getCaffeineSubtypes().forEach(cacheType -> hints.reflection().registerType(TypeReference.of(cacheType),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS)));
}
private Set<String> getCaffeineSubtypes() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
try {
provider.addIncludeFilter(new AssignableTypeFilter(Class.forName(CAFFEINE_BOUNDED_LOCAL_CACHE_CLASS_NAME)));
provider.addIncludeFilter(new AssignableTypeFilter(Class.forName(CAFFEINE_NODE_CLASS_NAME)));
}
catch (ClassNotFoundException e) {
LOG.warn("Could not get class for name: " + CAFFEINE_BOUNDED_LOCAL_CACHE_CLASS_NAME);
}
return provider.findCandidateComponents(CAFFEINE_CACHE_BASE_PACKAGE).stream().filter(Objects::nonNull)
.map(BeanDefinition::getBeanClassName).filter(Objects::nonNull).collect(Collectors.toSet());
}
}

2
spring-cloud-loadbalancer/src/main/resources/META-INF/spring/aot.factories

@ -0,0 +1,2 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
org.springframework.cloud.loadbalancer.config.CaffeineHints

1
spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfigurationTests.java

@ -38,7 +38,6 @@ import static org.assertj.core.api.Assertions.assertThat;
* *
* @author Olga Maciaszek-Sharma * @author Olga Maciaszek-Sharma
*/ */
class LoadBalancerCacheAutoConfigurationTests { class LoadBalancerCacheAutoConfigurationTests {
@Test @Test

Loading…
Cancel
Save