hank-cp / sbp Goto Github PK
View Code? Open in Web Editor NEWPlugin framework for Spring Boot based on pf4j.
License: Apache License 2.0
Plugin framework for Spring Boot based on pf4j.
License: Apache License 2.0
例如 我插件plugins-a 我想他的所有接口都是以/plugins-a开头 但是我并不想在每个controller里面都写/plugins-a/xxx/xxx
Eg
pf4j
The plugins are stored in a folder. You can specify the plugins folder in the constructor of DefaultPluginManager. If the plugins folder is not specified then the location is returned by System.getProperty("pf4j.pluginsDir", "plugins").
NOTE: The “pf4j.pluginsDir” property comes with comma-separated directory list support (support for multiple plugin root directories).
The structure of plugins folder is:
plugin1.zip (or plugin1 folder)
plugin2.zip (or plugin2 folder)
But the SpringBootPluginManager constructor only supports single Path
public SpringBootPluginManager(Path pluginsRoot) {
super(pluginsRoot);
}
(Machine translation may be inaccurate, hope to understand)
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?
Spring Boot 3.0 changes a lot from 2.X:
javax.*
change to jakarta
Hello,
I've identified an issue with the management of the plugins lifecycle.
I have three plugins A, B and C. The plugins B and C depends on the plugin A.
Initially, the three plugins A, B and C are started. Then I do the following actions (actions order is important).
I'm not sure if it's a SBP issue or a PF4J issue (?).
This issue can be reprocuded easily, but an existing example already exists here.
Hello,
I try to create a test project to run plugin in spring application with sbp. (repo with the code here => https://github.com/dtrouillet/sbp-test )
My problem is that my plugin won't run.
I have this stacktrace :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-11-08 22:48:01.929 ERROR 91165 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
APPLICATION FAILED TO START
Description:
Field pluginManager in fr.trouillet.devportal.PluginController required a bean of type 'org.pf4j.PluginManager' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
The following candidates were found but could not be injected:
- Bean method 'pluginManager' in 'SbpAutoConfiguration' not loaded because auto-configuration 'SbpAutoConfiguration' was excluded
- Bean method 'pluginManager' in 'SbpAutoConfiguration' not loaded because auto-configuration 'SbpAutoConfiguration' was excluded
Action:
Consider revisiting the entries above or defining a bean of type 'org.pf4j.PluginManager' in your configuration.
2020-11-08 22:48:01.941 ERROR 91165 --- [ main] org.laxture.sbp.SpringBootPluginManager : Error creating bean with name 'pluginController': Unsatisfied dependency expressed through field 'pluginManager'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.pf4j.PluginManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Thanks a lot
Caused by: java.lang.ClassCastException: class org.laxture.sbp.spring.boot.SbpAutoConfiguration$1 cannot be cast to class org.laxture.sbp.SpringBootPluginManager (org.laxture.sbp.spring.boot.SbpAutoConfiguration$1 is in unnamed module of loader 'app'; org.laxture.sbp.SpringBootPluginManager is in unnamed module of loader org.pf4j.PluginClassLoader @69d3cf7e)
at org.laxture.sbp.SpringBootPlugin.getPluginManager(SpringBootPlugin.java:183) ~[sbp-core-0.1.13.jar:na]
at org.laxture.sbp.SpringBootPlugin.getMainApplicationContext(SpringBootPlugin.java:187) ~[sbp-core-0.1.13.jar:na]
at org.laxture.sbp.spring.boot.SpringBootstrap.(SpringBootstrap.java:238) ~[sbp-core-0.1.13.jar:na]
at com.plugin.dynamic.DynamicPlugin.createSpringBootstrap(DynamicPlugin.java:15) ~[na:na]
at org.laxture.sbp.SpringBootPlugin.(SpringBootPlugin.java:73) ~[sbp-core-0.1.13.jar:na]
at com.plugin.dynamic.DynamicPlugin.(DynamicPlugin.java:10) ~[na:na]
... 25 common frames omitted
It happens when I am trying to load a plugin from the *.zip.
application.yml:
`spring.sbp:
enabled: true
runtimeMode: deployment
customPluginLoader: org.pf4j.DefaultPluginLoader
classes-directories:
Now we can only add dependency to main application pom.
i want to use dubbo as a service into a plugin, can i use this framework to do it?
Thank you for your response, I have been able to start the plugin and have access to the endpoint inside the plugin. but pls can you explain how I can stop and update the plugin. And connect each plugin to the data base of the core. It was not that written in the Read Me file. Thank you.
I'm encountering multiple bean initialization issues in a Spring Boot 3.x project using sbp version 3.1.22. The primary challenge involves an UnsatisfiedDependencyException
, starting with the SpringBootPluginManager
bean and persisting with others.
Steps to Reproduce:
sbp-spring-boot-starter
in the dependencies.application.properties
as per sbp guidelines.plugins
directory.I've basically followed the guide on readme.
Errors Encountered:
The application fails to start, initially due to an UnsatisfiedDependencyException
for SpringBootPluginManager
. The error message indicates a missing bean:
2024-04-02T09:34:56.200+03:00 ERROR 40304 --- [pluginDemo] [ main] o.laxture.sbp.SpringBootPluginManager : Error creating bean with name 'pluginManagerController': Unsatisfied dependency expressed through field 'pluginManager': No qualifying bean of type 'org.laxture.sbp.SpringBootPluginManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'pluginManagerController': Unsatisfied dependency expressed through field 'pluginManager': No qualifying bean of type 'org.laxture.sbp.SpringBootPluginManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
...
Resolving this leads to similar issues with other beans.
Attempted Solutions:
spring.factories
.PluginManager
bean.scanBasePackages
.None of these attempts have successfully resolved the bean initialization issues.
Additional Context:
The problem seems to extend beyond a specific bean, suggesting a more systemic issue with the sbp setup or compatibility.
I have set up a GitHub repository for detailed inspection of the project.
Request for Assistance:
Guidance or suggestions to resolve these bean initialization challenges would be greatly appreciated.
Not seeing unit tests for core, plugin, etc classes. Looks like there is recent work for sb 3.0. Looks good. Thanks
Hello,
I'm currently interested in integrating htmx-spring-boot; it's a set of helpers to work with htmx
and avoid some boilerplate, the library provides a custom class that extends RequestMappingHandlerMapping
for intercepting htmx
specific endpoints.
If I add the dependencies and just run my example repo I would get a ClassCastException
, I've tried adding the property plugin.pluginFirstClasses=HtmxRequestMappingHandlerMapping
and plugin.pluginFirstClasses=io.github.wimdeblauwe.htmx.spring.boot.mvc.HtmxRequestMappingHandlerMapping
to the config without any luck, maybe I didn't understand the right way to use this?
So my question is, if I were to integrate this library permanently without relaying in the config for it, how should proceed? Should I create a custom WebMvcRegistrations
bean to override the one in SbpWebMvcPatchAutoConfiguration
and provide an extended PluginRequestMappingHandlerMapping
class that also to included the htmx
handling? Or what would be a right way of handling this?
Salutations and thanks.
I've tried the prop in application-context spring.sbp.custom-plugin-loaders
.
It appends custom loaders to the list of pre-existing loaders. So custom loaders can't apply for files with extension .zip or .jar, because the loading is prevented by pre-existing loaders.
So the custom loader should apply for files with different extension, but it's not possible, because the file discovering is accomplished by fileFilter
in PluginRepository
and there is no way to add custom pluginRepository.
Could you allow to set plugin repositories as you done with plugin loaders?
Let me say my opinion: maybe It's too limited to customize the SpringBootPluginManager only through properties in application.yml. The force of pf4j is the high grade of customization by class inheritance. Why is it not possible to extend your SpringBootPluginManager and declare it as bean preventing the creation in the sbp library? after all there is a @ConditionalOnMissingBean
in SbpAutoConfiguration
.
Hi,
I tried to setup a (very) simple/dummy test project in order to test your library but I'm still not able to load my application.
The source code is available here: https://github.com/j-barata/marketbasket-sbp-sample.
Actually when I try to run the application (through IntelliJ IDEA), I get the following stack and although I've read the documentation many times, I can't see what I'm doing wrong. do you have an idea ?
2020-07-26 21:34:21.133 INFO 45051 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2700 ms
2020-07-26 21:34:21.412 INFO 45051 --- [ main] org.pf4j.DefaultPluginStatusProvider : Enabled plugins: []
2020-07-26 21:34:21.414 INFO 45051 --- [ main] org.pf4j.DefaultPluginStatusProvider : Disabled plugins: []
2020-07-26 21:34:21.421 INFO 45051 --- [ main] org.pf4j.DefaultPluginManager : PF4J version 3.1.0 in 'development' mode
2020-07-26 21:34:21.436 INFO 45051 --- [ main] org.pf4j.AbstractPluginManager : Plugin 'com.github.market.basket.sbp.sample.plugins.tomatoes@1.0.0-SNAPSHOT' resolved
2020-07-26 21:34:21.436 INFO 45051 --- [ main] org.pf4j.AbstractPluginManager : Plugin 'com.github.market.basket.sbp.sample.plugins.potatoes@1.0.0-SNAPSHOT' resolved
2020-07-26 21:34:21.437 INFO 45051 --- [ main] org.pf4j.AbstractPluginManager : Start plugin 'com.github.market.basket.sbp.sample.plugins.tomatoes@1.0.0-SNAPSHOT'
2020-07-26 21:35:44.484 ERROR 45051 --- [ main] org.pf4j.DefaultPluginFactory : com.github.market.basket.sbp.sample.plugins.tomatoes.TomatoesPlugin
java.lang.ClassNotFoundException: com.github.market.basket.sbp.sample.plugins.tomatoes.TomatoesPlugin
at org.laxture.sbp.internal.SpringBootPluginClassLoader.loadClassFromDependencies(SpringBootPluginClassLoader.java:156) ~[sbp-core-0.1.5.jar:na]
at org.laxture.sbp.internal.SpringBootPluginClassLoader.loadClass(SpringBootPluginClassLoader.java:101) ~[sbp-core-0.1.5.jar:na]
at org.pf4j.DefaultPluginFactory.create(DefaultPluginFactory.java:46) ~[pf4j-3.1.0.jar:3.1.0]
at org.pf4j.PluginWrapper.getPlugin(PluginWrapper.java:79) ~[pf4j-3.1.0.jar:3.1.0]
at org.pf4j.AbstractPluginManager.startPlugins(AbstractPluginManager.java:331) ~[pf4j-3.1.0.jar:3.1.0]
at org.laxture.sbp.SpringBootPluginManager.init(SpringBootPluginManager.java:122) ~[sbp-core-0.1.5.jar:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1304) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:893) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551) ~[spring-context-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.1.RELEASE.jar:2.3.1.RELEASE]
at com.github.market.basket.sbp.sample.application.MarketBasketApplication.main(MarketBasketApplication.java:35) ~[classes/:na]
Hello,
I get the follow error message:
The bean 'resourceHandlerRegistrationCustomizer', defined in class path resource [org/laxture/sbp/spring/boot/SbpMvcPatchAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$ResourceChainCustomizerConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
The Action is not a Solution. Than I get another error message.
I use Spring Boot Version 2.6.8 and sbp-spring-boot-starter Version 0.1.13
Can you help me?
Hello,
In my plugins I've defined some service classes that implement an interface (and also provided a bean allowing to instantiate the service classes).
In the application I try to autowire these interfaces but I only get :
Field <> in <> Component required a bean of type '<>' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
It seems that the beans providing these components have not been recognized... or maybe I've missed something.
I already successfully tested the plugin manager "getExtensions" way, but now I would like to use the autowired annotation.
Is it supported ?
Thanks
Hello there, quite new to pf4j and sbp. So I'm probably just missing something.
I'm trying to move an existing pf4j application to sbp. However, when starting the plugin-container, I receive an IllegalArgumentException from spring. According to the stack-trace, the responsible spring boot method is directly called by sbp.
I've tried to specify spring-profiles int the container, as well as in the loaded test-plugin, however, that seems not to be the profiles, spb is using.
Is there any way to specify the used profiles / make that array not null?
spring-boot-starter-parent: 2.2.6.RELEASE
sbp-core: 0.1.3
java: 11
Logs:
sbp.log
Hello,
I'm trying to setup a resource provider within a plugin (the resources shall be provided by the plugin itself), and tried the following code :
@configuration
@EnableWebMvc
public class ImageProvider implements WebMvcConfigurer {
@OverRide
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/icons/*").addResourceLocations("classpath:/icons/");
}
}
But I only get a 404 Error
.
Is this kind of feature currently supported ?
Thanks
Frist ,I have a plugin use springboot and thymeleaf,it can run .
but when the application load it , it's error like
Error resolving template [search_index], template might not exist or might not be accessible by any of the configured Template Resolvers
具体不爽的点:
ClassLoadingStrategy
),我实现的时候也没有用这套。但是SpringBootPluginClassLoader这个类实现的真丑,明明内部loadClass可以按约定先平台、后插件jar,居然还提供pluginFirstClasses让调用者关心细节。SpringBootstrap也没有指定父容器的classLoader新项目已经被我重新实现了,仍然是spring+p4j,如果想看我也可以放出源码
Hi there,
Trying to read plugin-name.properties
in plugin jar file using PropertySource
.
@PropertySource(value = "file:${admin-ui.home}/config/plugin-name.properties")
But it shows the below message when the plugin is started.
java -jar hans-admin-ui-api-standalone.jar --admin-ui.home=D:\Projects\java\hans-admin-ui-api
Logs
2021-02-25 18:02:58.338 INFO 11584 --- [ main] o.s.c.a.ConfigurationClassParser : Properties location [file:${admin-ui.home}/config/plugin-name.properties] not resolvable: Could not resolve placeholder 'admin-ui.home' in value "file:${admin-ui.home}/config/plugin-name.properties"
We have also used admin-ui.home
placeholder in the parent project. It is working there.
Is that possible to load a plugin from a external jar at runtime?
For example, to haveg an app with a REST API as below:
@RequestMapping(value = "/installplugin", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public void install(@RequestBody(required = true) MultipartFile file) {
URLClassLoader child = new URLClassLoader(
new URL[] {myJar.toURI().toURL()},
this.getClass().getClassLoader()
);
Class<?> clazz = Class.forName("mypackage.MyClass", true, loader);
// pesudo code
pluginManager.load(clazz);
pluginManager.start("plugin-id");
}
then mypackage.MyClass (as a plugin) is a RestController:
@RestController
@RequestMapping("/message")
public class MyClass {
@RequestMapping(value = "/return", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Message testMethod() {
return new Message("HIHIHIHI");
}
}
User should be able to call new endpoint with /message/return
after plugin being installed.
Missing artifact com.github.hank-cp:spring-static-ctx:jar:0.1.1
It's a transitive dependency imported by sbp-spring-boot-starter
and it's not in maven central repository.
Front End modularization How to achieve?
PluginResourceHandlerRegistrationCustomizer
changes a lot between Spring boot versions.implementation
to runtime
Hello!
Could you help me?
Error appeared, when I create bean for pluginManager
Error:(88, 23) java: cannot access org.laxture.sbp.SpringBootPluginManager
bad class file: /C:/m2/org/laxture/sbp-core/0.1.7/sbp-core-0.1.7.jar!/org/laxture/sbp/SpringBootPluginManager.class
class file has wrong version 55.0, should be 52.0
Please remove or make sure it appears in the correct subdirectory of the classpath.
Hi there,
Nice framework!
Are there any plans to support more recent versions of SpringBoot like 2.7.x?
Cheers!
How to get DataSource in main App from plugin ??
Or Plugin datasource withaut set on plugin(application.yaml)
Hello!
I tried to use SpringBootPlugin, but I have an error, when init SpringBootstrap at
super(new DefaultResourceLoader(plugin.getWrapper().getPluginClassLoader()), primarySources);
ConfigurationWarningsApplicationContextInitializer and ApplicationContextInitializer are under different Class Loader (PluginClassLoader and AppClassLoader) and SpringApplication.createSpringFactoriesInstances#Assert.isAssignable(type, instanceClass); fails
What should I do? Thank you!
Now we can only add dependency to main application pom.
So, I'm trying to understand how to use the "Single shared DataSource", as described in the persistence documentation.
I have two plugins, one responsible for storing libraries and a second one for storing videos.
I'm using the SharedDataSourceSpringBootstrap within the SpringBootPlugin class in both plugins like so:
public class LibraryPlugin extends SpringBootPlugin {
public LibraryPlugin(final PluginWrapper wrapper) {
super(wrapper);
}
@Override
protected SpringBootstrap createSpringBootstrap() {
return new SharedDataSourceSpringBootstrap(this, LibraryStarter.class);
}
}
And create the Entities as usual, however, separated into the two different plugins.
The Video entity contains a reference to the Library entity as follows:
@Entity
public class Video {
@Id
private long id;
@OneToOne
@MapsId
@JoinColumn(name = "library")
private Library library;
}
When starting the system, the video-plugins exits with the following cause:
Caused by: org.hibernate.MappingException: An association from the table video refers to an unmapped class: com.example.plugins.library.Library
Now, as hibernate thinks that the plugin is unmapped and both plugins are running their own hibernate instance, where they can't see the other classes.
Is this even supposed to work?
In the end, the persistence documentation never states that the data source is also shared between plugins (i just assumed since both plugins are using the data source from the main-application)
Do I have to include SharedDataSourceSpringBootstrap somewhere within the main-application?
I have not seen anything that hints to something like that, but as the data-source is probably still separated.
Edit:
Forgot to mention, but i've added the plugin dependency to both, maven and plugin.properties
I've tried to define a custom plugin manager
@Configuration
public class AppConfig {
@Bean
public SpringBootPluginManager pluginManager() {
return new CustomPluginManager();
}
...
}
public class CustomPluginManager extends SpringBootPluginManager {
...
}
and I got this error:
Caused by: java.lang.ClassCastException: class org.mypackage.CustomPluginManager cannot be cast
to class org.laxture.sbp.SpringBootPluginManager (org.mypackage.CustomPluginManager is in
unnamed module of loader 'app'; org.laxture.sbp.SpringBootPluginManager is in unnamed module
of loader org.pf4j.PluginClassLoader @69228e85)
How can I define a CustomPluginManager that extends SpringBootPluginManager
?
You've published spring-static-ctx
with groupId org.laxture
but cdb-core looks for com.github.hank-cp:spring-static-ctx
.
我的環境是 Java8
測試的倉庫在這
Springboot 版本為 2.7.17
Sbp 版本為 2.7.17
不管在 development mode 還是在 deployment mode
只要 Plugin 的啟動器使用 @SpringBootApplication
標籤 ( 例如這樣 )
運行時就會出現
2023-11-14 17:52:21.153 DEBUG 24704 --- [ main] o.l.s.i.PluginListableBeanFactory : Creating shared instance of singleton bean 'resourceHandlerRegistrationCustomizer'
2023-11-14 17:52:21.170 WARN 24704 --- [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'resourceHandlerRegistrationCustomizer': Unsatisfied dependency expressed through field 'webProperties'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.web.WebProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
2023-11-14 17:52:21.176 INFO 24704 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2023-11-14 17:52:21.216 ERROR 24704 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field webProperties in org.springframework.boot.autoconfigure.web.servlet.PluginResourceHandlerRegistrationCustomizer required a bean of type 'org.springframework.boot.autoconfigure.web.WebProperties' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.boot.autoconfigure.web.WebProperties' in your configuration.
2023-11-14 16:36:53.849 ERROR 28064 --- [ main] org.laxture.sbp.SpringBootPluginManager : Error creating bean with name 'resourceHandlerRegistrationCustomizer': Unsatisfied dependency expressed through field 'webProperties'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.web.WebProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'resourceHandlerRegistrationCustomizer': Unsatisfied dependency expressed through field 'webProperties'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.web.WebProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:713) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:693) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:408) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:921) [spring-context-5.3.30.jar:5.3.30]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) [spring-context-5.3.30.jar:5.3.30]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) ~[spring-boot-2.7.17.jar:2.7.17]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:409) ~[spring-boot-2.7.17.jar:2.7.17]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-2.7.17.jar:2.7.17]
at org.laxture.sbp.SpringBootPlugin.start(SpringBootPlugin.java:99) ~[sbp-core-2.7.17.jar:na]
at org.laxture.sbp.SpringBootPluginManager.doStartPlugins(SpringBootPluginManager.java:149) [sbp-core-2.7.17.jar:na]
at org.laxture.sbp.SpringBootPluginManager.startPlugins(SpringBootPluginManager.java:232) [sbp-core-2.7.17.jar:na]
at org.laxture.sbp.internal.MainAppStartedListener.onApplicationEvent(MainAppStartedListener.java:43) [sbp-core-2.7.17.jar:na]
at org.laxture.sbp.internal.MainAppStartedListener.onApplicationEvent(MainAppStartedListener.java:31) [sbp-core-2.7.17.jar:na]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178) [spring-context-5.3.30.jar:5.3.30]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171) [spring-context-5.3.30.jar:5.3.30]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:145) [spring-context-5.3.30.jar:5.3.30]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421) [spring-context-5.3.30.jar:5.3.30]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378) [spring-context-5.3.30.jar:5.3.30]
at org.springframework.boot.context.event.EventPublishingRunListener.started(EventPublishingRunListener.java:108) [spring-boot-2.7.17.jar:2.7.17]
at org.springframework.boot.SpringApplicationRunListeners.lambda$started$5(SpringApplicationRunListeners.java:78) [spring-boot-2.7.17.jar:2.7.17]
at java.util.ArrayList.forEach(ArrayList.java:1259) ~[na:1.8.0_265]
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120) [spring-boot-2.7.17.jar:2.7.17]
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:114) [spring-boot-2.7.17.jar:2.7.17]
at org.springframework.boot.SpringApplicationRunListeners.started(SpringApplicationRunListeners.java:78) [spring-boot-2.7.17.jar:2.7.17]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) ~[spring-boot-2.7.17.jar:2.7.17]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.7.17.jar:2.7.17]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) ~[spring-boot-2.7.17.jar:2.7.17]
at com.xeriou.robotapp.RobotAppApplication.main(RobotAppApplication.java:15) ~[classes/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.web.WebProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1801) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1357) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311) ~[spring-beans-5.3.30.jar:5.3.30]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:710) ~[spring-beans-5.3.30.jar:5.3.30]
... 36 common frames omitted
但是,只要將啟動改成@ComponentScan
(例如這樣) 就不會出錯,且運行不會有問題。
但這樣會導致 DataSource 的 Bean 沒有辦法共用 (在 pluginx 裡)
且開發上,無法獨立運行,挺不方便的
我看大家都沒出甚麼問題,可能是我設定方式不對...
Configuration :
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@EnableSwagger2 in Configuration class
Error
Ambiguous mapping. Cannot map 'springfox.documentation.oas.web.OpenApiControllerWebMvc@64c5516e' method \nspringfox.documentation.oas.web.OpenApiControllerWebMvc#getDocumentation(String, HttpServletRequest)\nto {GET [/v3/api-docs], produces [application/json || application/hal+json]}: There is already 'openApiControllerWebMvc' bean method\nspringfox.documentation.oas.web.OpenApiControllerWebMvc#getDocumentation(String, HttpServletRequest) mapped.
When I use spring-dev-tools my api interface is in a different class loader : RestartClassLoader managed by Spring Dev Tools.
With this library, my Plugin can't upcasted in my API Interface (ClassCastException) because the API Interface is in other class loader (RestartClassLoader).
For now I remove spring-dev-tools in my prject.
Now sbp supports WebMVC only. Need to investigate how to support WebFlux.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.