Closed raphw closed 7 years ago
I am rather wary of making this too easy to do as, without it, parts of Tomcat will break. Unless you know what you're doing, the chance of shooting yourself in the foot could be quite high. That said, I believe it's only of relevance when using Tomcat embedded in a .war
file.
Out of interest, what sort of app are your building where it isn't needed? Also, have you considered registering a user factory with TomcatURLStreamHandlerFactory
?
For testing a bunch of microservices, I want to avoid spinning up a seperate process for every service but rather isolate those services by class loader. The services are rather simple and short-lived, therefore, they work just fine this way.
However, I need to disable this to avoid clashes in the URL
registration. I find it generally a bad pattern to rely on this VM global, maybe this should be addressed in Tomcat but I would still appreciate the option.
Given that disabling this is a single line of code, I'm not sure what better option we could provide. It doesn't feel like the sort of thing that would generally benefit from being externally configurable (via application.properties, for example). You said above that it's "difficult to hook in that early". Can you not call disable in your application's main method (prior to calling run
) or in the code that's creating each ClassLoader that you're using for isolation?
We have quite a bunch of services which import a custom configuration that handles some general configuration like token security and so on. It would rather heavy for us to maintain this in the application start method whereas it would be easy to add this to a profile-specific yaml file in the common module.
You are however right about that I could probably just locate the class in the class loader that isolates the application. I was however struggeling to understand if this is compatible with Spring Boot's fat jar concept. I will try it, though! Thanks for the hint.
I will try it, though! Thanks for the hint.
Great, thanks. Please let us know how it works out. If it doesn't work, we can look at alternatives.
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
I finally tried this and unfortunately, it is not that easy. The application is started via the Spring Boot Launcher such that Tomcat ends up on another class loader. From a generic starter, I cannot interact with any classes of the application before running Spring Boot where I would need to inject some class into the application jar to modify the application.
That's a shame. Thanks for following up.
I'm still of the opinion that this is an edge case that doesn't warrant a configuration property. For this to be a problem you need to be running multiple instances of Tomcat in the same JVM with a ClassLoader arrangement that means that Tomcat's classes are loaded on two or more different ClassLoaders.
As you've noted, disabling Tomcat's TomcatURLStreamHandlerFactory
is a matter of making single method call at an appropriate time. Spring Boot provides more than one mechanism for doing so as part of an application being launched. You can use SpringApplicationRunListener
as you've already noted. You could also use an ApplicationListener
registered in spring.factories
that listens for the ApplicationEnvironmentPreparedEvent
.
When running Tomcat embedded, it registers its
TomcatURLStreamHandlerFactory
in theURL::setURLStreamHandlerFactory
. This factory can only be set once globally on the VM. Therefore, this can raise conflicts with other libraries that do the same.Would you consider adding a property such that I can simply disable this in the startup? It is difficult to hook in that early, I do now use a
SpringApplicationRunListener
but it would be nice if there was something ready-made.Disabling it is as easy as calling
TomcatURLStreamHandlerFactory.disable()
before starting the server for the first time.Thanks!