hank-cp / sbp

Plugin framework for Spring Boot based on pf4j.
Apache License 2.0
213 stars 68 forks source link

ClassNotFoundException for plugin class, loading a spring boot executable jar #10

Open fabioformosa opened 4 years ago

fabioformosa commented 4 years ago

I'm testing the deployment runtime-mode. Main App finds plugin jar that I put in plugins folder, but it fails when it tries to switch plugin state from RESOLVED to STARTED because:

java.lang.ClassNotFoundException: com.example.MyPlugin

I put the spring boot fat jar, built by spring-boot-maven-plugin that creates the following structure into the jar:

Managing plugins with the shape of spring boot application, is SBP library aware to search classes under BOOT-INF folder?

hank-cp commented 4 years ago

I have commit demonstration code of building plugin jar. Please checkout https://github.com/hank-cp/sbp/commit/9107e87656026d30c7e0461c45254aad303a5bbf for more details. Also, you could read the doc describe further more.

Regarding to

Managing plugins with the shape of spring boot application, is SBP library aware to search classes under BOOT-INF folder?

the quick answer is no. I recommand search plugins jar via file system, rather than searching classpath. It's design to load/unload plugins dynamically at runtime time. If you use classpath, sbp has not difference as other ordinary monolithic Spring Boot application.

fabioformosa commented 4 years ago

I recommand search plugins jar via file system, rather than searching classpath

I'm added the plugin jar via file system, but my jar is a spring boot executable jar, not a standard jar. Look at this link to browser the structure of a spring boot executable jar: https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-executable-jar-format.html#executable-jar-jar-file-structure

You've done a wonderful work with this library, but since it addresses pluggability of spring boot apps, I'm expecting that it's possible to provide via filesystem a spring boot executable jar because it's a standard way to build for spring.

So, according your opinion, loading a plugin jar with that structure, is it possibile to specify to sbp plugin loader the path (inside jar): /BOOT-INF/classes and /BOOT-INF/libs? I've tried with classes-directories properties but it doesn't work in deployment mode.

EDIT: I've just tried to load a standard jar (not spring boot executable jar ) assembling manually it with "libs" and it run OK. I think it could be more convenient to load a spring boot executable jar, because it contains all libs by default.

hank-cp commented 4 years ago

got your point.

I think this could be done by add a custom PluginLoader. Right now SbpAutoConfiguration.pluginManager use two PluginLoader as here and here. You could implement an ExecutableJarPluginLoader to locate the dependent jars in BOOT-INFO/libs, and then add it to SbpAutoConfiguration.pluginManager by overridding it.

fabioformosa commented 4 years ago

Thank you for the answer. Now, it's clear to me how to define a new PluginLoader in the PluginManager bean. I think that the ExecutableJarPluginLoader should use an extended version of your SpringBootPluginClassLoader. Could you help me to understand which method to override in SpringBootPluginClassLoader to locate (inside the jar) classes and libs into the folders BOOT-INFO/classes and BOOT-INFO/libs ?

hank-cp commented 4 years ago

I have just added a configuration spring.sbp.custom-plugin-loaders to allow you customize your own PluginLoader (example)

You could use the SNAPSHOT version to experience it.

fabioformosa commented 4 years ago

Good, so it's easier to add a custom plugin loader. Very nice! But I don't understand yet how to develop this custom plugin loader to load classes from a jar with the structure of a spring-executable-jar. It should be like the native JarPluginLoader but with an extendend SpringBootPluginClassLoader, I suppose. Which method should I override in SpringBootPluginClassLoader to locate (inside the jar) classes and libs into the folders BOOT-INFO/classes and BOOT-INFO/libs ?

hank-cp commented 4 years ago

I don't suggest you to extend SpringBootPluginClassLoader. There are complex class loading strategies behind it.

What you have to do now is to load jars inside a jar. Looks like there are no out-of-box solution till today(can't believe that >_<!). Here is antoher example.

Then you could implement a custom FatJarPluginLoader, who holds the PluginClassLoader, and tell this PluginClassLoader to load the jars by pluginClassLoader.addFile(myJarFile); just as other PluginLoader did.

fabioformosa commented 4 years ago

What you have to do now is to load jars inside a jar

Not only jars, also the classes are in another folder (BOOT-INF/classes) inside the plugin.jar

fabioformosa commented 4 years ago

With spring.sbp.custom-plugin-loaders does the CustomPluginLoader replace the default ones or add itself to the list of default loaders?

hank-cp commented 4 years ago

adding, after the builtin pluginLoader DefaultPluginLoader/JarPluginLoader

fabioformosa commented 4 years ago

Ok, I would need to remove/replace JarPluginLoader because it's apply to all jars. I would like to have an extended JarPluginLoader that supports standard jar and spring boot jar.

hank-cp commented 4 years ago

Have make custom-plugin-loader exclusive as #13 mentioned.

wuyuan2009123 commented 11 months ago

i also get same error

hank-cp commented 10 months ago

@wuyuan2009123 For a fatJar plugin, you need to unzip the jar and load classes/libs seperator. Or you can build your jar in flatten format.

This issue is still open because it is still waiting a workable FatJar example...

luanact247 commented 5 months ago

@fabioformosa finally, how to fix this issue? I get this issue too. Could you show me how to resolve it?