详解如何给Sprintboot应用添加插件机制
场景
想要让boot应用增加插件能力,扩展restful api。插件可以由第三方开发
要解决的问题
- 第三方的api需要和主应用使用相同的pom依赖
- 第三方的api独立打包成jar包,并按照命名规则取名
- 第三方的api需要再boot应用之外的独立存储中放置(部署)
- 第三方的api jar 包的加载时机及方式
方案
- 独立的依赖管理 pom 第三方插件继承此pom 统一依赖
- api jar 包放置到特定路径。由boot 启动时加载。(也可以热加载,但实现方式复杂一些)
- 技术点 classloader 加载插件 jar, 类型需要添加到spring bean 中统一管理生命周期。
下面是classloader的实现
public class ClassLoaderUtil { public static ClassLoader getClassLoader(String url) { try { Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); if (!method.isAccessible()) { method.setAccessible(true); } URLClassLoader classLoader = new URLClassLoader(new URL[]{}, ClassLoader.getSystemClassLoader()); method.invoke(classLoader, new URL(url)); return classLoader; } catch (Exception e) { log.error("getClassLoader-error", e); return null; } } }
启动时将类加入到spring中
public class PluginImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { private final String targetUrl = "file:/D:/SpringBootPluginTest/plugins/plugin-impl-0.0.1-SNAPSHOT.jar"; private final String pluginClass = "com.plugin.impl.PluginImpl"; @SneakyThrows @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { ClassLoader classLoader = ClassLoaderUtil.getClassLoader(targetUrl); Class<?> clazz = classLoader.loadClass(pluginClass); BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); BeanDefinition beanDefinition = builder.getBeanDefinition(); registry.registerBeanDefinition(clazz.getName(), beanDefinition); } }
运行时将类加载到spring中,此时需要用ApplicationContextAware
@Component public class SpringUtil implements ApplicationContextAware { private DefaultListableBeanFactory defaultListableBeanFactory; private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext; this.defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory(); } public void registerBean(String beanName, Class<?> clazz) { BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz); defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getRawBeanDefinition()); } public Object getBean(String name) { return applicationContext.getBean(name); } }
做一个运行时加载的入口
@GetMapping("/reload") public Object reload() throws ClassNotFoundException { ClassLoader classLoader = ClassLoaderUtil.getClassLoader(targetUrl); Class<?> clazz = classLoader.loadClass(pluginClass); springUtil.registerBean(clazz.getName(), clazz); PluginInterface plugin = (PluginInterface)springUtil.getBean(clazz.getName()); return plugin.sayHello("test reload");
到此这篇关于详解如何给Sprintboot应用添加插件机制的文章就介绍到这了,更多相关Sprintboot应用添加插件机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Spring中@RestControllerAdvice注解的使用详解
这篇文章主要介绍了Spring中@RestControllerAdvice注解的使用详解,@RestControllerAdvice是一个组合注解,由@ControllerAdvice、@ResponseBody组成,而@ControllerAdvice继承了@Component,需要的朋友可以参考下2024-01-01testNG项目通过idea Terminal命令行执行的配置过程
这篇文章主要介绍了testNG项目通过idea Terminal命令行执行,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-07-07Spring中的之启动过程obtainFreshBeanFactory详解
这篇文章主要介绍了Spring中的之启动过程obtainFreshBeanFactory详解,在refresh时,prepareRefresh后,马上就调用了obtainFreshBeanFactory创建beanFactory以及扫描bean信息(beanDefinition),并通过BeanDefinitionRegistry注册到容器中,需要的朋友可以参考下2024-02-02IntellJ idea使用FileWatch实时编译less文件的方法
这篇文章主要介绍了IntellJ idea使用FileWatch实时编译less文件的相关资料,需要的朋友可以参考下2018-02-02Java图形化界面设计之布局管理器之BorderLayout案例详解
这篇文章主要介绍了Java图形化界面设计之布局管理器之BorderLayout案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下2021-08-08
最新评论