From d0f6d2b2e94025df6ea4a129bdb0d1c01c0195ab Mon Sep 17 00:00:00 2001 From: spencergibb Date: Wed, 21 Jun 2023 13:57:02 -0400 Subject: [PATCH 1/3] Uses a custom event to share the SpringApplication. Rather than RestartListener republishing the ApplicationPreparedEvent, a new event, ContextRefreshedWithApplicationEvent, is published with the data from the original event. Listeners were refactored to listen to the new event instead. Fixes gh-1248 --- .../ContextRefreshedWithApplicationEvent.java | 52 +++++++++++++++++++ .../refresh/ConfigDataContextRefresher.java | 6 +-- .../context/restart/RestartEndpoint.java | 8 +-- .../context/restart/RestartListener.java | 8 +-- .../restart/RestartIntegrationTests.java | 4 -- 5 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 spring-cloud-context/src/main/java/org/springframework/cloud/context/config/ContextRefreshedWithApplicationEvent.java diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/config/ContextRefreshedWithApplicationEvent.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/config/ContextRefreshedWithApplicationEvent.java new file mode 100644 index 00000000..1b3ac42b --- /dev/null +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/config/ContextRefreshedWithApplicationEvent.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2023 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.cloud.context.config; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.context.event.SpringApplicationEvent; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * A custom event for spring cloud context use cases that need the saved + * Spring Application. This prevents a duplicated ApplicationPreparedEvent + * from being republished. + */ +public class ContextRefreshedWithApplicationEvent extends SpringApplicationEvent { + + private final ConfigurableApplicationContext context; + + /** + * Create a new {@link ContextRefreshedWithApplicationEvent} instance. + * @param application the current application + * @param args the arguments the application is running with + * @param context the ApplicationContext about to be refreshed + */ + public ContextRefreshedWithApplicationEvent(SpringApplication application, String[] args, + ConfigurableApplicationContext context) { + super(application, args); + this.context = context; + } + + /** + * Return the application context. + * @return the context + */ + public ConfigurableApplicationContext getApplicationContext() { + return this.context; + } + +} diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/refresh/ConfigDataContextRefresher.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/refresh/ConfigDataContextRefresher.java index a8644c83..08fc45ce 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/context/refresh/ConfigDataContextRefresher.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/refresh/ConfigDataContextRefresher.java @@ -27,11 +27,11 @@ import org.springframework.boot.BootstrapRegistry; import org.springframework.boot.ConfigurableBootstrapContext; import org.springframework.boot.DefaultBootstrapContext; import org.springframework.boot.SpringApplication; -import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.logging.DeferredLogFactory; import org.springframework.boot.util.Instantiator; import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration; +import org.springframework.cloud.context.config.ContextRefreshedWithApplicationEvent; import org.springframework.cloud.context.scope.refresh.RefreshScope; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; @@ -45,7 +45,7 @@ import org.springframework.core.io.support.SpringFactoriesLoader; * @author Venil Noronha */ public class ConfigDataContextRefresher extends ContextRefresher - implements ApplicationListener { + implements ApplicationListener { private SpringApplication application; @@ -60,7 +60,7 @@ public class ConfigDataContextRefresher extends ContextRefresher } @Override - public void onApplicationEvent(ApplicationPreparedEvent event) { + public void onApplicationEvent(ContextRefreshedWithApplicationEvent event) { application = event.getSpringApplication(); } diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/restart/RestartEndpoint.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/restart/RestartEndpoint.java index a0463401..bbd841b6 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/context/restart/RestartEndpoint.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/restart/RestartEndpoint.java @@ -30,8 +30,8 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.SpringApplication; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.WriteOperation; -import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.ContextRefreshedWithApplicationEvent; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationEvent; @@ -51,7 +51,7 @@ import org.springframework.util.ClassUtils; * */ @Endpoint(id = "restart", enableByDefault = false) -public class RestartEndpoint implements ApplicationListener { +public class RestartEndpoint implements ApplicationListener { private static Log logger = LogFactory.getLog(RestartEndpoint.class); @@ -61,7 +61,7 @@ public class RestartEndpoint implements ApplicationListener Date: Wed, 21 Jun 2023 23:49:09 +0000 Subject: [PATCH 2/3] Bumping versions --- .../ContextRefreshedWithApplicationEvent.java | 6 +++--- .../core/ServiceInstanceListSupplierBuilder.java | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/config/ContextRefreshedWithApplicationEvent.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/config/ContextRefreshedWithApplicationEvent.java index 1b3ac42b..796bd0c4 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/context/config/ContextRefreshedWithApplicationEvent.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/config/ContextRefreshedWithApplicationEvent.java @@ -21,9 +21,9 @@ import org.springframework.boot.context.event.SpringApplicationEvent; import org.springframework.context.ConfigurableApplicationContext; /** - * A custom event for spring cloud context use cases that need the saved - * Spring Application. This prevents a duplicated ApplicationPreparedEvent - * from being republished. + * A custom event for spring cloud context use cases that need the saved Spring + * Application. This prevents a duplicated ApplicationPreparedEvent from being + * republished. */ public class ContextRefreshedWithApplicationEvent extends SpringApplicationEvent { diff --git a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplierBuilder.java b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplierBuilder.java index 3d0668fe..c6aa0f85 100644 --- a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplierBuilder.java +++ b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/ServiceInstanceListSupplierBuilder.java @@ -145,7 +145,7 @@ public final class ServiceInstanceListSupplierBuilder { public ServiceInstanceListSupplierBuilder withHealthChecks() { DelegateCreator creator = (context, delegate) -> { ReactiveLoadBalancer.Factory loadBalancerClientFactory = context - .getBean(LoadBalancerClientFactory.class); + .getBean(LoadBalancerClientFactory.class); WebClient.Builder webClient = context.getBean(WebClient.Builder.class); return healthCheckServiceInstanceListSupplier(webClient.build(), delegate, loadBalancerClientFactory); }; @@ -268,7 +268,7 @@ public final class ServiceInstanceListSupplierBuilder { } this.cachingCreator = (context, delegate) -> { ObjectProvider cacheManagerProvider = context - .getBeanProvider(LoadBalancerCacheManager.class); + .getBeanProvider(LoadBalancerCacheManager.class); if (cacheManagerProvider.getIfAvailable() != null) { return new CachingServiceInstanceListSupplier(delegate, cacheManagerProvider.getIfAvailable()); } @@ -334,7 +334,8 @@ public final class ServiceInstanceListSupplierBuilder { ReactiveLoadBalancer.Factory loadBalancerClientFactory) { return new HealthCheckServiceInstanceListSupplier(delegate, loadBalancerClientFactory, (serviceInstance, healthCheckPath) -> webClient.get() - .uri(UriComponentsBuilder.fromUriString(getUri(serviceInstance, healthCheckPath)).build().toUri()) + .uri(UriComponentsBuilder.fromUriString(getUri(serviceInstance, healthCheckPath)).build() + .toUri()) .exchange().flatMap(clientResponse -> clientResponse.releaseBody() .thenReturn(HttpStatus.OK.equals(clientResponse.statusCode())))); } @@ -344,12 +345,11 @@ public final class ServiceInstanceListSupplierBuilder { ReactiveLoadBalancer.Factory loadBalancerClientFactory) { return new HealthCheckServiceInstanceListSupplier(delegate, loadBalancerClientFactory, (serviceInstance, healthCheckPath) -> Mono.defer(() -> { - URI uri = UriComponentsBuilder.fromUriString(getUri(serviceInstance, healthCheckPath)) - .build() - .toUri(); + URI uri = UriComponentsBuilder.fromUriString(getUri(serviceInstance, healthCheckPath)).build() + .toUri(); try { return Mono - .just(HttpStatus.OK.equals(restTemplate.getForEntity(uri, Void.class).getStatusCode())); + .just(HttpStatus.OK.equals(restTemplate.getForEntity(uri, Void.class).getStatusCode())); } catch (Exception ignored) { return Mono.just(false); From a22bb12e75cb7c9a0cb7fbd52576e34cafafb579 Mon Sep 17 00:00:00 2001 From: Olga MaciaszekSharma Date: Mon, 26 Jun 2023 17:53:59 +0200 Subject: [PATCH 3/3] Add missing reflection hints for EncryptionBootstrapConfiguration. Fixes gh-1245. --- .../encrypt/EncryptionBootstrapConfiguration.java | 14 ++++++++++++++ .../main/resources/META-INF/spring/aot.factories | 2 ++ 2 files changed, 16 insertions(+) create mode 100644 spring-cloud-context/src/main/resources/META-INF/spring/aot.factories diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EncryptionBootstrapConfiguration.java b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EncryptionBootstrapConfiguration.java index b43bc0d4..ee25d77e 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EncryptionBootstrapConfiguration.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/encrypt/EncryptionBootstrapConfiguration.java @@ -16,6 +16,9 @@ package org.springframework.cloud.bootstrap.encrypt; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionOutcome; @@ -142,4 +145,15 @@ public class EncryptionBootstrapConfiguration { } + class EncryptionHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + hints.reflection().registerTypeIfPresent(classLoader, + "org.springframework.security.rsa.crypto.RsaSecretEncryptor", + MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + } + + } + } diff --git a/spring-cloud-context/src/main/resources/META-INF/spring/aot.factories b/spring-cloud-context/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 00000000..8663a91e --- /dev/null +++ b/spring-cloud-context/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ +org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration.EncryptionHints \ No newline at end of file