Problem:
I have a custom implementation of java.util.prefs in a maven jar module.
I am providing the system property to -djava.util.prefs.PreferencesFactory=com.blah.CustomePrefsFactory
to my Spring boot app that is using the custom preferences.
When the Spring boot app uses the Preferences for the first time, the Java.util.Preferences.java tries to load the CustomePrefsFactory using the
ClassLoader.getSystemClassLoader().
This results in errors as nested jar classes are not available to a system class loader of the spring boot app.
Is there a way to make nested jar classes available to the system class loader?
The short answer is no.
System ClassLoader delegates to the Bootstrap ClassLoader and Extension ClassLoader and then tries to load classes from classpath, but not from nested JARs.
You have to implement or use an existing ClassLoader that supports that functionality.
Related
We are using plugin architecture for one of our projects and we decided to use Spring pf4j for the same.
When we load the plugin via extensions - the application context is not able to find the beans created using #component in the plugin project- but the beans declared in #configuration classes are injected properly when we configure the plugin using register method - Is there anyway to scan and load the spring components in the plugin?
#Component in plugin is registered to main ApplicationContext via SpringExtensionFactory, make sure you set it up correctly in DefaultPluginManager correctly.
If you are going to use pf4j in SpringBoot, I would suggest you take a look sbp project. It is built upon pf4j and provides better integration with SpringBoot.
I have a Spring Boot Jersey Application. I want to use a custom class loader with it to allow loading classes and resources from outside of standard web application classpath. (I need it to allow customers to add "plugins" to the application without disturbing original application file structure). Any suggestions how can I do that?
I am running a spring application.
My requirement is user will be placing a plugin jar file at run time at designated lib folder location.
This plugin jar file will have spring application context file as well. I want to load this jar, means all the classes - spring beans
and all its dependent beans/components(this is important), from this jar file at run time.
I do not want to create new/child application context and want to use the existing spring bean context loaded at application start up.
I reffered to few other similar threads/questions on SO and could resolve the issue of dynamically loading of spring beans.
But i am not able to resolve issue of loading all the dependent beans for the spring beans.
Could you please provide any pointers/hints to dynamically load all the dependent beans of spring bean(which is also)loaded at run time?
Thanks in advance,
Picku
If you want to be able to load the plugin after startup you are not going to get away with not creating another application context as a child.
I'd suggest you do exactly this and then create some hooks in parent context whereby your plugin will integrate itself.
The alternative is to include that plugin.jar in the main classpath and then restart the application to include the plugin.
(This is primarily a history question. Pivotal recommended that all forum discussions take place on StackOverflow, which is why I am asking it here.)
What are the reasons that the Spring Boot project used to justify moving an application's classes and dependencies from the "top level" of the executable jar format to be underneath BOOT-INF/?
Just trying to guess, it seems that this makes it easy to extract only the application-related classes and jars from the fat jar with a simple java -xf the-jar.jar BOOT-INF/classes command. Was that it? Was there some other reason?
TL;DR
Packaging application classes in the root of the jar required Spring Boot's class loader to use an unconventional delegation model and also caused problems with Java agents.
Detailed explanation
When a jar file is launched with java -jar all of the classes in the root of the jar are on the class path of the system class loader. In a Spring Boot fat jar, this includes the classes for the launcher which is responsible for creating a class loader that can load the application's classes and their dependencies that are nested inside the fat jar.
In Spring Boot 1.3 and earlier, application classes are packaged in the root of a fat jar file. This means that they are on the class path of the system class loader. With a standard, parent first delegation model this would mean that application classes would be loaded by the system class loader rather than Spring Boot's class loader. This is problematic as it's only Spring Boot's class loader that can load the classes from the dependencies that are nested inside the fat jar. The result being that the application cannot load the classes of any of its dependencies.
Spring Boot 1.3 overcame this problem by using an unconventional delegation model for its class loader. It created a new class loader using the URLs from the system class loader but not using the system class loader as a parent – the system class loader's parent was used instead. This meant that Spring Boot's class loader would be used to load the application's classes in the root of the jar and the classes of the application's dependencies in the nested jars.
This approach had some drawbacks. The first was that it made Spring Boot's class loader rather complex. The second was that it broke a number of assumptions that Java agents make with regards to how their classes will be loaded. We worked around a couple of these but it became clear that we were fighting a losing battle.
Spring Boot 1.4 rearranges a fat jar to place application classes in BOOT-INF/classes (it also moves nested jars to BOOT-INF/lib but that has no effect from a class loading perspective). Moving the application classes into BOOT-INF/classes means that they are no longer on the class path of the system class loader. This means that Spring Boot's class loader can be configured to load classes from BOOT-INF/classes and from within the jars in BOOT-INF/lib and use the system class loader as its parent. Java agents can be packaged in the root of the jar from where they'll be loaded by the system class loader as usual.
For further reading you may be interested in the message on the commit that introduced the change and the other issues to which it links.
I have a Spring-enabled OSGi bundle. I'd like this bundle to export a factory-type OSGi service which client software can use to create multiple instances of the application context defined in this bundle.
By default the Spring DM library bundles will automatically scan and create an instance of an application context from any Spring XML configuration found under "META_INF/spring". To avoid this I moved the Spring XML configuration files under a different folder and then tried creating the application context programmatically on demand from the factory class. Unfortunately I ran into issues with Spring schema files not being available on the bundle classpath. I really don't want to embed the required Spring jars within my bundle just to get access to those schemas.
Is there a simpler way to clone Spring application contexts under an OSGi environment?
I do not understand your problem in detail but if you just want to load the application-context from a different location than META-INF/spring you can define this in the MANIFEST.MF file using 'Spring-Context', e.g. for files in the root folder
Spring-Context: /application-context-core.xml,/application-context-osgi.xml
See the documentation for further information.