详解如何给Sprintboot应用添加插件机制
作者:陈sir的知识库
这篇文章主要为大家介绍了如何给 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应用添加插件机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!