CrazyAirhead

疯狂的傻瓜,傻瓜也疯狂——傻方能执著,疯狂才专注!

0%

Solon —— 插件

说明

Solon 是典型的微内核架构,通过框架核心提供了插件的核心接口和生命周期的管理。在之前的应用的生命周期中讲到过插件的三个生命时机点。通过这三个时机点,插件开发人员可以管理插件的资源初始化与资源的销毁。

Solon 的插件支持三种形式的运行方式:

  1. Spi 方式。是基于插件和配置声明的扩展方式,类似Spring Factories,主应用需要增加对插件的依赖。
  2. E-Spi 方式,也叫体外扩展。是基于插件和动态配置的扩展方式,类似Springboot-plugin-fraework,主程序不需要增加对插件的依赖。
  3. H-Spi 方式,也叫热插拔扩展。是基于插件和手动管理的扩展方式,类似Springboot-plugin-fraework,主程序不需要增加对插件的依赖。

这三种扩展方式对于开发插件本身没有什么区别,主要的区别是主应用的依赖和配置等,和实现的效果的不同,具体的特性对比可以参看官网 https://solon.noear.org/article/441 相关的文章。

插件涉及的示例代码包含多个模块,具体参看 https://gitee.com/CrazyAirhead/porpoise-demo:

  • demo-solon03-plugin Solon 插件
  • demo-solon03-main01 Solon 主应用 Spi
  • demo-solon03-main02 Solon 主应用 E-Spi
  • demo-solon03-main03 Solon 主应用 H-Spi

插件 demo-solon03-plugin

实现 hello 的基础功能。

实现 Plugin 接口

这里为了简单,直接扫描了插件包的 Bean 对象,在实际的开发过程中可根据实际的实现使用Conetext的其他方法构建 Bean,或者订阅 Bean,或者加载配置文件等,来完成实际的插件初始化操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.example.demo.solon.plugin;

import org.noear.solon.core.AppContext;
import org.noear.solon.core.Plugin;

/**
* @author airhead
*/
public class DemoSolonPlugin implements Plugin {
@Override
public void start(AppContext context) throws Throwable {
// 简单起见,直接扫描插件所在包,可以根据实际的需要进行定制化的加载
context.beanScan(DemoSolonPlugin.class);
}

@Override
public void prestop() throws Throwable {
Plugin.super.prestop();
}

@Override
public void stop() throws Throwable {
// 移除http处理。在热插拔的插件中特别
Solon.app().router().remove("/hello");
}
}

实现 Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.demo.solon.plugin.controller;

import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Param;

/**
* @author airhead
*/
@Controller
public class DemoController {
@Mapping("/hello")
public String hello(@Param(defaultValue = "world") String name) {
return String.format("Hello %s!", name);
}
}

配置插件文件

resources/META-INF/solon/ 目录下创建插件配置文件,文件名要在应用范围内全局唯一,为了避免冲突可以使用插件的包名做了文件名。

这里使用是META-INF/solon/com-example-demo-solon-plugin.properties,文件内容如下:

1
2
3
4
# 插件实现类
solon.plugin=com.jishunetwork.ficus.framework.server.XPluginImp
# 插件加载优先级,越大越优先,默认为0
solon.plugin.priority=1

这里常见的问题:文件目录错误,注解检查是二级目录,目录名是/META-INF/solon/;插件的实现类写错,可以通过点击的方式看下能否正常跳转到对应的类上来验证配置是否正确。

Spi demo-solon03-main01

只要添加对应的依赖即可不需要其他额外的配置。

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
dependencies {
implementation platform(project(":demo-parent"))

implementation("org.noear:solon-web")
implementation("org.noear:solon-logging-logback")
implementation("org.noear:solon-openapi2-knife4j")
implementation(project(":demo-solon03-plugin"))

annotationProcessor("org.mapstruct:mapstruct-processor:${mapstructVersion}")

testImplementation("org.noear:solon-test-junit5")
}

验证

调用插件实现的接口,http://127.0.0.1:8080/hello,返回hello world!

E-Spi demo-solon03-main02

只要添加修改配置,把插件放入指定文件夹路径即可。

配置

此时把插件目录放在jar相对路径的plugin下。

1
solon.extend: "!plugin"

注意:在idea中可能一下不能区分plugin再那个目录,可以先运行一次让 Solon 把目录创建出来,然后再把插件放到 plugin 目录下,此时我们可以看到是在 build/classes/java/main 目录下。把demo-solon03-plugin的插件放入plugin 目录后重新启动程序(注意此时不能再clean了,否则 刚放入的文件又被清理了)。

img

验证

调用插件实现的接口,http://127.0.0.1:8080/hello,返回hello world!

H-Spi demo-solon03-main03

热插拔的就是允许应用可以更灵活的管理插件的生命周期,因为热插拔是完全隔离的,因此需要自己更严格的管理资源的,更独立,避免与别的组件交互,避免不可拔的情况。

依赖

1
2
3
4
5
6
7
8
9
10
11
12
dependencies {
implementation platform(project(":demo-parent"))

implementation("org.noear:solon-web")
implementation("org.noear:solon-logging-logback")
implementation("org.noear:solon-openapi2-knife4j")
implementation("org.noear:solon-hotplug")

annotationProcessor("org.mapstruct:mapstruct-processor:${mapstructVersion}")

testImplementation("org.noear:solon-test-junit5")
}

配置

这里使用 Solon 默认提供的配置来管理,在加载的插件的过程中,只要能找到插件就可以了,不一定需要使用这个配置,注意路径是绝对路径。

1
2
solon.hotplug:
demo: /plugin/demo-solon03-plugin-1.0.0.jar

实现管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.example.demo.solon.controller;

import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.hotplug.PluginManager;

/**
* @author airhead
*/
@Controller
@Slf4j
public class PluginController {
@Mapping("start")
public String start() {
PluginManager.start("demo");
return "ok";
}

@Mapping("stop")
public String stop() {
PluginManager.stop("demo");
return "ok";
}
}

验证

  1. 调用插件实现的接口,http://127.0.0.1:8080/hello,此时不可访问
  2. 调用启动插件接口,http://127.0.0.1:8080/start,返回ok
  3. 调用插件实现的接口,http://127.0.0.1:8080/hello,此时返回 hello world
  4. 调用停止插件接口,http://127.0.0.1:8080/stop,返回ok
  5. 调用插件实现的接口,http://127.0.0.1:8080/hello,此时不可访问

小结

通过 Solon 提供的插件机制能简单、弹性、自由的实现功能扩展,既可以做框架型的插件开发,也可以做业务性的插件开发。

欢迎关注我的其它发布渠道