Skip to content

Commit fce9e44

Browse files
Merge branch 'main' into fix-issue-45001
Signed-off-by: Dmytro Danilenkov <[email protected]>
2 parents 3ca2d29 + 62e145e commit fce9e44

File tree

37 files changed

+756
-142
lines changed

37 files changed

+756
-142
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/observation/graphql/GraphQlObservationAutoConfiguration.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
3030
import org.springframework.context.annotation.Bean;
3131
import org.springframework.graphql.execution.GraphQlSource;
3232
import org.springframework.graphql.observation.DataFetcherObservationConvention;
33+
import org.springframework.graphql.observation.DataLoaderObservationConvention;
3334
import org.springframework.graphql.observation.ExecutionRequestObservationConvention;
3435
import org.springframework.graphql.observation.GraphQlObservationInstrumentation;
3536

@@ -49,9 +50,10 @@ public class GraphQlObservationAutoConfiguration {
4950
@ConditionalOnMissingBean
5051
public GraphQlObservationInstrumentation graphQlObservationInstrumentation(ObservationRegistry observationRegistry,
5152
ObjectProvider<ExecutionRequestObservationConvention> executionConvention,
52-
ObjectProvider<DataFetcherObservationConvention> dataFetcherConvention) {
53+
ObjectProvider<DataFetcherObservationConvention> dataFetcherConvention,
54+
ObjectProvider<DataLoaderObservationConvention> dataLoaderObservationConvention) {
5355
return new GraphQlObservationInstrumentation(observationRegistry, executionConvention.getIfAvailable(),
54-
dataFetcherConvention.getIfAvailable());
56+
dataFetcherConvention.getIfAvailable(), dataLoaderObservationConvention.getIfAvailable());
5557
}
5658

5759
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/observation/graphql/GraphQlObservationAutoConfigurationTests.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2023 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
2525
import org.springframework.context.annotation.Bean;
2626
import org.springframework.context.annotation.Configuration;
2727
import org.springframework.graphql.observation.DefaultDataFetcherObservationConvention;
28+
import org.springframework.graphql.observation.DefaultDataLoaderObservationConvention;
2829
import org.springframework.graphql.observation.DefaultExecutionRequestObservationConvention;
2930
import org.springframework.graphql.observation.GraphQlObservationInstrumentation;
3031
import org.springframework.graphql.server.WebGraphQlHandler;
@@ -71,6 +72,8 @@ void instrumentationUsesCustomConventionsIfAvailable() {
7172
.isInstanceOf(CustomExecutionRequestObservationConvention.class);
7273
assertThat(instrumentation).extracting("dataFetcherObservationConvention")
7374
.isInstanceOf(CustomDataFetcherObservationConvention.class);
75+
assertThat(instrumentation).extracting("dataLoaderObservationConvention")
76+
.isInstanceOf(CustomDataLoaderObservationConvention.class);
7477
});
7578
}
7679

@@ -97,6 +100,11 @@ CustomDataFetcherObservationConvention customDataFetcherConvention() {
97100
return new CustomDataFetcherObservationConvention();
98101
}
99102

103+
@Bean
104+
CustomDataLoaderObservationConvention customDataLoaderConvention() {
105+
return new CustomDataLoaderObservationConvention();
106+
}
107+
100108
}
101109

102110
static class CustomExecutionRequestObservationConvention extends DefaultExecutionRequestObservationConvention {
@@ -107,6 +115,10 @@ static class CustomDataFetcherObservationConvention extends DefaultDataFetcherOb
107115

108116
}
109117

118+
static class CustomDataLoaderObservationConvention extends DefaultDataLoaderObservationConvention {
119+
120+
}
121+
110122
@Configuration(proxyBeanMethods = false)
111123
static class WebGraphQlConfiguration {
112124

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/ssl/SslHealthIndicator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,23 @@
2828
import org.springframework.boot.info.SslInfo.BundleInfo;
2929
import org.springframework.boot.info.SslInfo.CertificateChainInfo;
3030
import org.springframework.boot.info.SslInfo.CertificateInfo;
31+
import org.springframework.util.Assert;
3132

3233
/**
3334
* {@link HealthIndicator} that checks the certificates the application uses and reports
3435
* {@link Status#OUT_OF_SERVICE} when a certificate is invalid.
3536
*
3637
* @author Jonatan Ivanov
38+
* @author Young Jae You
3739
* @since 3.4.0
3840
*/
3941
public class SslHealthIndicator extends AbstractHealthIndicator {
4042

4143
private final SslInfo sslInfo;
4244

4345
public SslHealthIndicator(SslInfo sslInfo) {
46+
super("SSL health check failed");
47+
Assert.notNull(sslInfo, "'sslInfo' must not be null");
4448
this.sslInfo = sslInfo;
4549
}
4650

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationMetadataLoader.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
3333
*/
3434
final class AutoConfigurationMetadataLoader {
3535

36-
protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
36+
private static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";
3737

3838
private AutoConfigurationMetadataLoader() {
3939
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/AbstractHttpRequestFactoryProperties.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,12 @@ public void setFactory(Factory factory) {
4848

4949
/**
5050
* Return a {@link ClientHttpRequestFactoryBuilder} based on the properties.
51+
* @param classLoader the class loader to use for detection
5152
* @return a {@link ClientHttpRequestFactoryBuilder}
5253
*/
53-
protected final ClientHttpRequestFactoryBuilder<?> factoryBuilder() {
54+
protected final ClientHttpRequestFactoryBuilder<?> factoryBuilder(ClassLoader classLoader) {
5455
Factory factory = getFactory();
55-
return (factory != null) ? factory.builder() : ClientHttpRequestFactoryBuilder.detect();
56+
return (factory != null) ? factory.builder() : ClientHttpRequestFactoryBuilder.detect(classLoader);
5657
}
5758

5859
/**

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/HttpClientAutoConfiguration.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.List;
2020

21+
import org.springframework.beans.factory.BeanClassLoaderAware;
2122
import org.springframework.beans.factory.ObjectProvider;
2223
import org.springframework.boot.autoconfigure.AutoConfiguration;
2324
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -47,13 +48,20 @@
4748
@ConditionalOnClass(ClientHttpRequestFactory.class)
4849
@Conditional(NotReactiveWebApplicationCondition.class)
4950
@EnableConfigurationProperties(HttpClientProperties.class)
50-
public class HttpClientAutoConfiguration {
51+
public class HttpClientAutoConfiguration implements BeanClassLoaderAware {
52+
53+
private ClassLoader beanClassLoader;
54+
55+
@Override
56+
public void setBeanClassLoader(ClassLoader classLoader) {
57+
this.beanClassLoader = classLoader;
58+
}
5159

5260
@Bean
5361
@ConditionalOnMissingBean
5462
ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(HttpClientProperties httpClientProperties,
5563
ObjectProvider<ClientHttpRequestFactoryBuilderCustomizer<?>> clientHttpRequestFactoryBuilderCustomizers) {
56-
ClientHttpRequestFactoryBuilder<?> builder = httpClientProperties.factoryBuilder();
64+
ClientHttpRequestFactoryBuilder<?> builder = httpClientProperties.factoryBuilder(this.beanClassLoader);
5765
return customize(builder, clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());
5866
}
5967

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/AbstractClientHttpConnectorProperties.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ protected HttpClientSettings httpClientSettings(ObjectProvider<SslBundles> sslBu
5555
return super.httpClientSettings(sslBundles);
5656
}
5757

58+
/**
59+
* Return a {@link ClientHttpConnectorBuilder} based on the properties.
60+
* @param classLoader the class loader to use for detection
61+
* @return a {@link ClientHttpConnectorBuilder}
62+
*/
5863
protected final ClientHttpConnectorBuilder<?> connectorBuilder(ClassLoader classLoader) {
5964
Connector connector = getConnector();
6065
return (connector != null) ? connector.builder() : ClientHttpConnectorBuilder.detect(classLoader);

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/FileWatcher.java

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.nio.file.WatchKey;
2929
import java.nio.file.WatchService;
3030
import java.time.Duration;
31+
import java.util.Collections;
3132
import java.util.HashSet;
3233
import java.util.List;
3334
import java.util.Map;
@@ -85,71 +86,75 @@ void watch(Set<Path> paths, Runnable action) {
8586
this.thread = new WatcherThread();
8687
this.thread.start();
8788
}
88-
Set<Path> registrationPaths = new HashSet<>();
89-
for (Path path : paths) {
90-
registrationPaths.addAll(getRegistrationPaths(path));
91-
}
92-
this.thread.register(new Registration(registrationPaths, action));
89+
this.thread.register(new Registration(getRegistrationPaths(paths), action));
9390
}
9491
catch (IOException ex) {
9592
throw new UncheckedIOException("Failed to register paths for watching: " + paths, ex);
9693
}
9794
}
9895
}
9996

100-
@Override
101-
public void close() throws IOException {
102-
synchronized (this.lock) {
103-
if (this.thread != null) {
104-
this.thread.close();
105-
this.thread.interrupt();
106-
try {
107-
this.thread.join();
108-
}
109-
catch (InterruptedException ex) {
110-
Thread.currentThread().interrupt();
111-
}
112-
this.thread = null;
113-
}
114-
}
115-
}
116-
11797
/**
11898
* Retrieves all {@link Path Paths} that should be registered for the specified
11999
* {@link Path}. If the path is a symlink, changes to the symlink should be monitored,
120100
* not just the file it points to. For example, for the given {@code keystore.jks}
121101
* path in the following directory structure:<pre>
122-
* .
123-
* ├── ..a72e81ff-f0e1-41d8-a19b-068d3d1d4e2f
124-
* │ ├── keystore.jks
125-
* ├── ..data -> ..a72e81ff-f0e1-41d8-a19b-068d3d1d4e2f
126-
* ├── keystore.jks -> ..data/keystore.jks
102+
* +- stores
103+
* | +─ keystore.jks
104+
* +- <em>data</em> -&gt; stores
105+
* +─ <em>keystore.jks</em> -&gt; data/keystore.jks
127106
* </pre> the resulting paths would include:
107+
* <p>
128108
* <ul>
129-
* <li><b>keystore.jks</b></li>
130-
* <li><b>..data/keystore.jks</b></li>
131-
* <li><b>..data</b></li>
132-
* <li><b>..a72e81ff-f0e1-41d8-a19b-068d3d1d4e2f/keystore.jks</b></li>
109+
* <li>{@code keystore.jks}</li>
110+
* <li>{@code data/keystore.jks}</li>
111+
* <li>{@code data}</li>
112+
* <li>{@code stores/keystore.jks}</li>
133113
* </ul>
134-
* @param path the path
114+
* @param paths the source paths
135115
* @return all possible {@link Path} instances to be registered
136116
* @throws IOException if an I/O error occurs
137117
*/
138-
private static Set<Path> getRegistrationPaths(Path path) throws IOException {
139-
path = path.toAbsolutePath();
118+
private Set<Path> getRegistrationPaths(Set<Path> paths) throws IOException {
140119
Set<Path> result = new HashSet<>();
120+
for (Path path : paths) {
121+
collectRegistrationPaths(path, result);
122+
}
123+
return Collections.unmodifiableSet(result);
124+
}
125+
126+
private void collectRegistrationPaths(Path path, Set<Path> result) throws IOException {
127+
path = path.toAbsolutePath();
141128
result.add(path);
142129
Path parent = path.getParent();
143130
if (parent != null && Files.isSymbolicLink(parent)) {
144131
result.add(parent);
145-
Path target = parent.resolveSibling(Files.readSymbolicLink(parent));
146-
result.addAll(getRegistrationPaths(target.resolve(path.getFileName())));
132+
collectRegistrationPaths(resolveSiblingSymbolicLink(parent).resolve(path.getFileName()), result);
147133
}
148134
else if (Files.isSymbolicLink(path)) {
149-
Path target = path.resolveSibling(Files.readSymbolicLink(path));
150-
result.addAll(getRegistrationPaths(target));
135+
collectRegistrationPaths(resolveSiblingSymbolicLink(path), result);
136+
}
137+
}
138+
139+
private Path resolveSiblingSymbolicLink(Path path) throws IOException {
140+
return path.resolveSibling(Files.readSymbolicLink(path));
141+
}
142+
143+
@Override
144+
public void close() throws IOException {
145+
synchronized (this.lock) {
146+
if (this.thread != null) {
147+
this.thread.close();
148+
this.thread.interrupt();
149+
try {
150+
this.thread.join();
151+
}
152+
catch (InterruptedException ex) {
153+
Thread.currentThread().interrupt();
154+
}
155+
this.thread = null;
156+
}
151157
}
152-
return result;
153158
}
154159

155160
/**
@@ -254,6 +259,9 @@ public void close() throws IOException {
254259

255260
/**
256261
* An individual watch registration.
262+
*
263+
* @param paths the paths being registered
264+
* @param action the action to take
257265
*/
258266
private record Registration(Set<Path> paths, Runnable action) {
259267

@@ -265,6 +273,7 @@ boolean manages(Path file) {
265273
private boolean isInDirectories(Path file) {
266274
return this.paths.stream().filter(Files::isDirectory).anyMatch(file::startsWith);
267275
}
276+
268277
}
269278

270279
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -79,11 +79,10 @@ RestClientBuilderConfigurer restClientBuilderConfigurer(
7979
ObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder,
8080
ObjectProvider<ClientHttpRequestFactorySettings> clientHttpRequestFactorySettings,
8181
ObjectProvider<RestClientCustomizer> customizerProvider) {
82-
RestClientBuilderConfigurer configurer = new RestClientBuilderConfigurer();
83-
configurer.setRequestFactoryBuilder(clientHttpRequestFactoryBuilder.getIfAvailable());
84-
configurer.setRequestFactorySettings(clientHttpRequestFactorySettings.getIfAvailable());
85-
configurer.setRestClientCustomizers(customizerProvider.orderedStream().toList());
86-
return configurer;
82+
return new RestClientBuilderConfigurer(
83+
clientHttpRequestFactoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect),
84+
clientHttpRequestFactorySettings.getIfAvailable(ClientHttpRequestFactorySettings::defaults),
85+
customizerProvider.orderedStream().toList());
8786
}
8887

8988
@Bean

0 commit comments

Comments
 (0)