Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConnectionDetailsFactories should use the context class loader to load factories #45014

Closed
wants to merge 1 commit into from

Conversation

lengors
Copy link
Contributor

@lengors lengors commented Apr 6, 2025

Add flag to determine whether to use context class loader or ConnectionDetailsFactory class loader in ConnectionDetailsFactories.

Implements #45010.

I introduced a new constructor in ConnectionDetailsFactories that allows selecting between the thread’s context class loader and the ConnectionDetailsFactory class's class loader. retains the previous behavior to ensure backward compatibility.

Additionally, I extended DockerComposeProperties with a new flag (defaulting to false) that reflects this setting. The DockerComposeServiceConnectionsApplicationListener now uses this flag when creating the ConnectionDetailsFactories.

I chose this approach to maintain the old behavior by default. If there's consensus that always using the thread’s context class loader is sufficient, I’m happy to simplify the implementation accordingly.

Add flag to determine whether to use context class loader or
ConnectionDetailsFactory class loader on ConnectionDetailsFactories.

Signed-off-by: lengors <24527258+lengors@users.noreply.github.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Apr 6, 2025
@philwebb philwebb changed the title Add flag to ConnectionDetailsFactories for context class loader Add flag to ConnectionDetailsFactories for context class loader Apr 8, 2025
@philwebb philwebb self-assigned this Apr 8, 2025
@philwebb philwebb added type: enhancement A general enhancement type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Apr 8, 2025
@philwebb philwebb changed the title Add flag to ConnectionDetailsFactories for context class loader ConnectionDetailsFactories should use the context class loader to load factories Apr 8, 2025
philwebb pushed a commit that referenced this pull request Apr 8, 2025
Update `ConnectionDetailsFactories` so that the context classloader
can be used to load factories.

See gh-45014

Signed-off-by: lengors <24527258+lengors@users.noreply.github.com>
philwebb added a commit that referenced this pull request Apr 8, 2025
Refine the submitted pull-request to remove the configuration
property with the assumption that the context classloader will
work for all cases.

See gh-45014
@philwebb philwebb closed this in 9eb5e2b Apr 8, 2025
@philwebb philwebb added this to the 3.5.0-RC1 milestone Apr 8, 2025
@philwebb
Copy link
Member

philwebb commented Apr 8, 2025

Thanks very much for the PR @lengors. I think it's possible to argue that this is a bug, however, it feels a little risky to fix in a patch release so I'm keeping the target to 3.5.

I've refined your contribution a little to remove the property support and always use the context classloader. I think this should be fine, but if we find it introduces problems we can consider reintroducing the property.

If you can, please give the 3.5.x SNAPSHOT a go when https://github.com/spring-projects/spring-boot/actions/runs/14342588861 has finished to check that it solves your problem. Thanks!

@lengors
Copy link
Contributor Author

lengors commented Apr 8, 2025

Thanks very much for the PR @lengors. I think it's possible to argue that this is a bug, however, it feels a little risky to fix in a patch release so I'm keeping the target to 3.5.

I've refined your contribution a little to remove the property support and always use the context classloader. I think this should be fine, but if we find it introduces problems we can consider reintroducing the property.

If you can, please give the 3.5.x SNAPSHOT a go when https://github.com/spring-projects/spring-boot/actions/runs/14342588861 has finished to check that it solves your problem. Thanks!

@philwebb Thanks for reviewing.

Correct me if I'm wrong but as it stands, on DockerComposeServiceConnectionsApplicationListener, the ConnectionDetailsFactories is being instantiated by passing null as the class loader to the constructor which then SpringFactoriesLoader replaces with its own class classloder, which isn't necessarily the same as the thread's context classloader, right?

This would match the test I did where the custom ConnectionDetails create with the docker-compose factory still does not get injected when using dev-tools.

That said, I think being able to specify the classloader to instantiate ConnectionDetailsFactories is already a good step in the right direction, so thank you.

@philwebb
Copy link
Member

philwebb commented Apr 8, 2025

Correct me if I'm wrong but as it stands, on DockerComposeServiceConnectionsApplicationListener, the ConnectionDetailsFactories is being instantiated by passing null as the class loader to the constructor which then SpringFactoriesLoader replaces with its own class classloder, which isn't necessarily the same as the thread's context classloader, right?

I think it should be OK, the factories code ends up being used here which call this ClassUtils method. That method calls getDefaultClassLoader() which should attempt to use the thread context class loader.

That being said, this stuff is quite hard to test so please let me know if you find things still aren't working as expected.

@lengors
Copy link
Contributor Author

lengors commented Apr 9, 2025

I think it should be OK, the factories code ends up being used here which call this ClassUtils method. That method calls getDefaultClassLoader() which should attempt to use the thread context class loader.

That being said, this stuff is quite hard to test so please let me know if you find things still aren't working as expected.

I've create a repository to illustrate the issue: https://github.com/lengors/spring-connection-details-factory-issue

But, I also take a look in the meantime, and I think the issue is here where, if the classloader passed to forResourceLocation/forDefaultResourceLocation is null, it will then be replaced by SpringFactoriesLoader.class.getClassLoader(), so by the time the ClassUtils method is invoked the classloader is not null anymore, and it will use the one pass to it rather than calling getDefaultClassLoader().

So, I think it needs to be explicitly passed to the forDefaultResourceLocation function (maybe even by invoking the getDefaultClassLoader() itself on the ConnectionDetailsFactories constructor).

@philwebb philwebb reopened this Apr 9, 2025
@philwebb
Copy link
Member

philwebb commented Apr 9, 2025

Oh no, I totally missed that code and it behaves differently than I expected. I think it might be done that way for back-compatibility reasons. I think that classloader is used there to load the factories files, and the other code is used to create the class. I'll run the sample you've provided and check.

@philwebb
Copy link
Member

philwebb commented Apr 9, 2025

It looks like we have a bug in Spring Framework causing cache pollution. I've submitted spring-projects/spring-framework#34732. I've also put a work around in commit 4af0ee2. With that in place, the sample application works.

Thanks for your persistence getting this fixed!

@philwebb philwebb closed this Apr 9, 2025
@lengors
Copy link
Contributor Author

lengors commented Apr 9, 2025

It looks like we have a bug in Spring Framework causing cache pollution. I've submitted spring-projects/spring-framework#34732. I've also put a work around in commit 4af0ee2. With that in place, the sample application works.

Thanks for your persistence getting this fixed!

I gave it a test on both the sample application I provided and on an actual application I'm developing and both seemingly work. I'll keep using the -SNAPSHOT build for now and will report back if I find any issues.

Thank you very much for the work you've put into this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants