Skip to content

Commit cc1e1cc

Browse files
lengorsphilwebb
authored andcommitted
Allow ConnectionDetailsFactories to use context class loader
Update `ConnectionDetailsFactories` so that the context classloader can be used to load factories. See gh-45014 Signed-off-by: lengors <[email protected]>
1 parent 2e8999e commit cc1e1cc

File tree

3 files changed

+61
-12
lines changed

3 files changed

+61
-12
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/service/connection/ConnectionDetailsFactories.java

+37-1
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,26 @@ public class ConnectionDetailsFactories {
4747

4848
private final List<Registration<?, ?>> registrations = new ArrayList<>();
4949

50+
/**
51+
* Create a new {@link ConnectionDetailsFactories} instance. This constructor uses the
52+
* class loader of {@link ConnectionDetailsFactory} class to load the factories.
53+
*/
5054
public ConnectionDetailsFactories() {
51-
this(SpringFactoriesLoader.forDefaultResourceLocation(ConnectionDetailsFactory.class.getClassLoader()));
55+
this(false);
56+
}
57+
58+
/**
59+
* Create a new {@link ConnectionDetailsFactories} instance. This constructor takes a
60+
* boolean argument to determine whether the context class loader should be used to
61+
* load the factories. If {@code true} and the context class loader is available it
62+
* will be used otherwise the class loader of {@link ConnectionDetailsFactory} class
63+
* will be used.
64+
* @param useContextClassLoader if {@code true} and the context class loader is
65+
* available it will be used otherwise the class loader of
66+
* {@link ConnectionDetailsFactory} class will be used.
67+
*/
68+
public ConnectionDetailsFactories(boolean useContextClassLoader) {
69+
this(SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader(useContextClassLoader)));
5270
}
5371

5472
@SuppressWarnings({ "rawtypes", "unchecked" })
@@ -107,6 +125,24 @@ public <S> Map<Class<?>, ConnectionDetails> getConnectionDetails(S source, boole
107125
return List.copyOf(result);
108126
}
109127

128+
/**
129+
* Return the {@link ClassLoader} to use for loading factories.
130+
* <p>
131+
* The default implementation returns the context class loader of the current thread
132+
* or the class loader of this class if the context class loader is {@code null}.
133+
* @param useContextClassLoader if {@code true} and the context class loader is
134+
* available it will be used otherwise the class loader of
135+
* {@link ConnectionDetailsFactory} class will be used
136+
* @return the class loader to use for loading factories
137+
*/
138+
private static ClassLoader getClassLoader(boolean useContextClassLoader) {
139+
if (!useContextClassLoader) {
140+
return ConnectionDetailsFactory.class.getClassLoader();
141+
}
142+
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
143+
return (classLoader != null) ? classLoader : getClassLoader(false);
144+
}
145+
110146
/**
111147
* A {@link ConnectionDetailsFactory} registration.
112148
*

spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ public class DockerComposeProperties {
4646
*/
4747
private boolean enabled = true;
4848

49+
/**
50+
* Whether to try to use the context class loader for connection details factories.
51+
*/
52+
private boolean useContextClassLoader = false;
53+
4954
/**
5055
* Arguments to pass to the Docker Compose command.
5156
*/
@@ -89,10 +94,18 @@ public boolean isEnabled() {
8994
return this.enabled;
9095
}
9196

97+
public boolean isUseContextClassLoader() {
98+
return this.useContextClassLoader;
99+
}
100+
92101
public void setEnabled(boolean enabled) {
93102
this.enabled = enabled;
94103
}
95104

105+
public void setUseContextClassLoader(boolean useContextClassLoader) {
106+
this.useContextClassLoader = useContextClassLoader;
107+
}
108+
96109
public List<String> getArguments() {
97110
return this.arguments;
98111
}
@@ -137,7 +150,7 @@ public Readiness getReadiness() {
137150
return this.readiness;
138151
}
139152

140-
static DockerComposeProperties get(Binder binder) {
153+
public static DockerComposeProperties get(Binder binder) {
141154
return binder.bind(NAME, DockerComposeProperties.class).orElseGet(DockerComposeProperties::new);
142155
}
143156

spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/DockerComposeServiceConnectionsApplicationListener.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
import org.springframework.boot.autoconfigure.container.ContainerImageMetadata;
2828
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
2929
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;
30+
import org.springframework.boot.context.properties.bind.Binder;
3031
import org.springframework.boot.docker.compose.core.RunningService;
32+
import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties;
3133
import org.springframework.boot.docker.compose.lifecycle.DockerComposeServicesReadyEvent;
3234
import org.springframework.context.ApplicationContext;
3335
import org.springframework.context.ApplicationListener;
@@ -46,32 +48,30 @@
4648
class DockerComposeServiceConnectionsApplicationListener
4749
implements ApplicationListener<DockerComposeServicesReadyEvent> {
4850

49-
private final ConnectionDetailsFactories factories;
50-
5151
DockerComposeServiceConnectionsApplicationListener() {
52-
this(new ConnectionDetailsFactories());
53-
}
5452

55-
DockerComposeServiceConnectionsApplicationListener(ConnectionDetailsFactories factories) {
56-
this.factories = factories;
5753
}
5854

5955
@Override
6056
public void onApplicationEvent(DockerComposeServicesReadyEvent event) {
6157
ApplicationContext applicationContext = event.getSource();
6258
if (applicationContext instanceof BeanDefinitionRegistry registry) {
59+
Binder binder = Binder.get(applicationContext.getEnvironment());
60+
DockerComposeProperties properties = DockerComposeProperties.get(binder);
61+
boolean useContextClassLoader = properties.isUseContextClassLoader();
62+
ConnectionDetailsFactories factories = new ConnectionDetailsFactories(useContextClassLoader);
6363
Environment environment = applicationContext.getEnvironment();
64-
registerConnectionDetails(registry, environment, event.getRunningServices());
64+
registerConnectionDetails(registry, environment, event.getRunningServices(), factories);
6565
}
6666
}
6767

6868
private void registerConnectionDetails(BeanDefinitionRegistry registry, Environment environment,
69-
List<RunningService> runningServices) {
69+
List<RunningService> runningServices, ConnectionDetailsFactories factories) {
7070
for (RunningService runningService : runningServices) {
7171
DockerComposeConnectionSource source = new DockerComposeConnectionSource(runningService, environment);
72-
this.factories.getConnectionDetails(source, false).forEach((connectionDetailsType, connectionDetails) -> {
72+
factories.getConnectionDetails(source, false).forEach((connectionDetailsType, connectionDetails) -> {
7373
register(registry, runningService, connectionDetailsType, connectionDetails);
74-
this.factories.getConnectionDetails(connectionDetails, false)
74+
factories.getConnectionDetails(connectionDetails, false)
7575
.forEach((adaptedType, adaptedDetails) -> register(registry, runningService, adaptedType,
7676
adaptedDetails));
7777
});

0 commit comments

Comments
 (0)