Solon v4.0.5

dubbo3-solon-plugin

</> markdown
2026年7月30日 下午6:29:36

此插件,主要社区贡献人(浅念)

<dependency>
    <groupId>org.noear</groupId>
    <artifactId>dubbo3-solon-plugin</artifactId>
</dependency>

1、描述

分布式扩展插件。基于 Apache Dubbo 3 适配的 RPC 集成插件,覆盖配置绑定、服务导出、服务引用与进程保活;子配置属性与 Dubbo 官方 Config 字段一致。

完整字段含义见:Dubbo 配置参考

2、快速开始

2.1 启用

启动类上必须标注 @EnableDubbo

@EnableDubbo
public class App {
    public static void main(String[] args) {
        Solon.start(App.class, args);
    }
}
注解用途
@DubboService暴露服务(兼容旧 @Service
@DubboReference注入消费代理(兼容旧 @Reference

仅标注 @DubboService 即可被扫描注册,无需额外加 @Component / @Managed

2.2 声明接口

public interface HelloService {
    String sayHello(String name);
}

2.3 提供者(服务端)

配置app.yml):

server.port: 8011

dubbo:
  application:
    name: hello-provider
    owner: noear
  registry:
    address: nacos://localhost:8848
  protocol:
    name: dubbo
    port: 20880

协议 port 未配置时默认取 server.port + 20000

代码

@EnableDubbo
public class DubboProviderApp {
    public static void main(String[] args) {
        Solon.start(DubboProviderApp.class, args);
    }
}

@DubboService(group = "hello")
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        return "hello, " + name;
    }
}

2.4 消费者(客户端)

@EnableDubbo
public class DubboConsumeApp {
    public static void main(String[] args) {
        Solon.start(DubboConsumeApp.class, args, app -> app.enableHttp(false));

        DubboConsumeApp tmp = Solon.context().getBean(DubboConsumeApp.class);
        System.out.println(tmp.home());
    }

    @DubboReference(group = "hello")
    HelloService helloService;

    public String home() {
        return helloService.sayHello("noear");
    }
}

3、配置总览

3.1 支持的配置前缀

前缀形态说明
dubbo.application应用信息;缺 name 时用 solon.app.group + - + solon.app.name
dubbo.registry / dubbo.registries单 / 多注册中心;缺 address 时补齐 N/A
dubbo.protocol / dubbo.protocols单 / 多协议;缺 namedubbo,缺 portserver.port + 20000
dubbo.provider / dubbo.providers单 / 多服务端默认;map key → id,可被 @DubboService(provider=...) 引用
dubbo.consumer / dubbo.consumers单 / 多消费端默认;map key → id,可被 @DubboReference(consumer=...) 引用
dubbo.monitor单 · 可选监控中心
dubbo.config-center单 · 可选配置中心
dubbo.metadata-report单 · 可选元数据中心
dubbo.solon.blockSolon 特有进程保活开关

未在上表中的前缀(如 metrics、module 等)当前不绑定

3.2 绑定规则

  1. 子键 = Dubbo Config 属性——例如 dubbo.registry.addressRegistryConfig.setAddress(...),与 Spring Boot 习惯一致。
  2. multi 优先于 single——存在 dubbo.registries / protocols / providers / consumers 时,忽略对应单数形式。
  3. map key → id——非数字 key 且未显式写 id 时,key 写入 config 的 id(便于注解引用)。
  4. list 索引 key——支持 registries.0 / registries[0];按索引排序,稳定有序。
  5. 缺省补全——仅对 registry(address)、protocol(name/port)、application(name)做插件级默认;provider/consumer 未配置时不创建默认实例。

3.3 常用字段速查

配置常用字段
applicationname, owner, logger, qos-enable, qos-port
registryaddress, username, password, group, timeout, check, simplified, parameters
protocolname, port, host, threads, serialization, transporter
providergroup, version, timeout, retries, filter, token, delay
consumergroup, version, timeout, check, retries, filter, scope, loadbalance
monitoraddress, protocol
config-centeraddress, protocol, namespace, group
metadata-reportaddress, protocol, group

4、多配置(Map 风格)

支持为不同服务指定不同的注册中心、协议和提供者/消费者默认值。

4.1 配置示例

dubbo:
  registries:
    reg1:
      address: zookeeper://127.0.0.1:2181
    reg2:
      address: nacos://127.0.0.1:8848
  protocols:
    dubbo:
      name: dubbo
      port: 20880
    triple:
      name: tri
      port: 50051
  providers:
    p1:
      group: g1
      timeout: 3000
    p2:
      group: g2
      filter: solonTracing
  consumers:
    c1:
      check: false
      timeout: 2000
    c2:
      check: false
      timeout: 5000

4.2 注解引用

Map key 自动写入 id,可在注解中按 id 引用:

@DubboService(
    provider = "p1",
    registry = {"reg1"},
    protocol = {"dubbo"}
)
public class HelloServiceImpl implements HelloService {
    // ...
}

@DubboReference(
    consumer = "c1",
    registry = {"reg1"},
    check = false
)
HelloService helloService;
注解属性结果
@DubboService(provider = "p1")设置 providerIds = p1;id 不存在则启动失败
@DubboReference(consumer = "c1")查找 ConsumerConfig(id=c1) 并关联;不存在则启动失败
registry = {"reg1", "reg2"}设置 registryIds = reg1,reg2;缺失 id 直接 fail-fast
@DubboService(protocol = {"dubbo", "tri"})设置 protocolIds = dubbo,tri(仅 Service 侧;Reference 用字符串 protocol

5、本地调试

5.1 不连注册中心(本地模式)

dubbo:
  registry:
    address: N/A
  consumer:
    scope: local    # 同进程本地调用
    check: false

5.2 双进程直连调试(推荐)

服务端配置:

# demo-server.yml
solon.app:
  group: demo
  name: dubbo-provider

dubbo:
  application:
    name: dubbo-provider
    logger: slf4j
  registry:
    address: N/A
  protocol:
    name: dubbo
    port: 20880
  provider:
    group: demo
@EnableDubbo
public class DubboProviderApp {
    public static void main(String[] args) {
        Solon.start(DubboProviderApp.class, args, app -> {
            app.enableHttp(false);  // 纯 Provider,由插件保活
        });
    }
}

@DubboService(group = "demo")
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(String name) {
        return "hello, " + name;
    }
}

客户端配置:

# demo-client.yml
solon.app:
  group: demo
  name: dubbo-consumer

dubbo:
  application:
    name: dubbo-consumer
    logger: slf4j
  registry:
    address: N/A
  consumer:
    check: false
    timeout: 3000
  solon:
    block: false   # 一次性 Consumer,执行完后退出

demo:
  hello:
    group: demo
    url: dubbo://127.0.0.1:20880
@EnableDubbo
public class DubboConsumeApp {
    @DubboReference(
        group = "${demo.hello.group}",
        url = "${demo.hello.url}",
        check = false
    )
    HelloService helloService;

    public static void main(String[] args) {
        Solon.start(DubboConsumeApp.class, args, app -> {
            app.enableHttp(false);
        });

        DubboConsumeApp app = Solon.context().getBean(DubboConsumeApp.class);
        String result = app.helloService.sayHello("noear");
        System.out.println("result = " + result);

        Solon.stopBlock(false, 0);  // 执行完毕,退出进程
    }
}

客户端通过 ${...} 模板从配置文件中动态读取 group 和 url,无需硬编码。

6、进程保活

纯 Dubbo Provider 进程(不开 HTTP)需要插件保活,否则 main 线程结束后进程会退出。

场景行为
dubbo.solon.block = true/false显式开关,优先
enableHttp(false) / 无 HTTP默认后台线程保活(纯 Provider)
HTTP 开启(Solon 默认)不额外保活,依赖 HTTP 服务器线程

建议:

  • 纯 Provider:配置 app.enableHttp(false),插件自动保活
  • 一次性 Consumer:配置 dubbo.solon.block: false,避免 main 结束后仍被保活

7、高级注解特性

7.1 ${...} 配置模板

所有 String 类型的注解属性(如 groupversionurltoken 等)都支持 ${...} 模板,从配置文件中取值:

# app.yml
demo.service.group: g1
demo.service.version: 1.0.0
@DubboService(
    group = "${demo.service.group}",
    version = "${demo.service.version}"
)
public class HelloServiceImpl implements HelloService { ... }

7.2 parameters(参数)

支持灵活的格式:

@DubboService(
    group = "demo",
    parameters = {"token", "abc", "route=gray"}  // → {token=abc, route=gray}
)
public class HelloServiceImpl implements HelloService { ... }

@DubboReference(
    group = "demo",
    parameters = {"tag:gray"}  // 也支持冒号分隔
)
HelloService helloService;
写法结果
{"a","b"}{a=b}
{"a=b"}{a=b}
{"a:b"}{a=b}
{"a=b","c","d"}{a=b, c=d}
{"a","a:b"}{a=a:b}

奇数不成对会报错;值支持 ${...} 模板。

7.3 methods(方法级配置)

@DubboService(
    group = "demo",
    methods = {
        @Method(name = "sayHello", timeout = 1000, retries = 0)
    }
)
public class HelloServiceImpl implements HelloService { ... }

@DubboReference(
    group = "demo",
    methods = {
        @Method(name = "sayHello", timeout = 2000)
    }
)
HelloService helloService;

7.4 远程引用建议

启动期创建代理时若强依赖注册中心,可能导致启动失败。建议:

  • 配置 dubbo.consumer.check: false,或
  • 注解 check = false,或
  • 显式 url = "dubbo://host:port" 直连

8、行为说明

说明
服务导出扫描阶段只注册 ServiceConfig;统一在 lifecycle 中 DubboBootstrap.start() 真正导出
接口解析优先 interfaceName / interfaceClass;否则取实现类直接业务接口(不展开父接口;多接口时保留最具体者);0 个或仍有歧义则启动失败
默认 application.namesolon.app.group + - + solon.app.name
默认 registry未配置 address → N/A
默认 protocol未配置 name → dubbo;未配置 port → server.port + 20000
multi 引用注解 provider / consumer / registry[] / Service protocol[] 按 id 关联;缺失 fail-fast
Reference 缓存相同 interface / group / version / url / protocol / scope / consumerId / registryIds / filter 等关键参数复用代理
停机preStopbootstrap.stop() 并清理引用缓存

9、Tracing(链路追踪)

已注册 Dubbo Filter SPI:solonTracing

存在 OpenTracing Tracer bean 时,可通过 filter 启用:

dubbo:
  provider:
    filter: solonTracing
  consumer:
    filter: solonTracing

也可写在 multi providers.* / consumers.*filter 上。

10、原生编译(AOT / GraalVM Native Image)

⚠️ 当前未完全验证通过,以下为参考配置。

添加 dubbo-native 依赖包(提供 AOT 处理实现)。dubbo-native AOT 编译时还会用到 spring-context。

<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-native</artifactId>
    <version>${dubbo3.version}</version>
</dependency>

添加 dubbo-maven-plugin 构建插件:

<profiles>
    <profile>
        <id>native-dubbo</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.dubbo</groupId>
                    <artifactId>dubbo-maven-plugin</artifactId>
                    <version>${dubbo3.version}</version>
                    <configuration>
                        <mainClass>com.example.nativedemo.NativeDemoApplication</mainClass>
                    </configuration>
                    <executions>
                        <execution>
                            <phase>process-sources</phase>
                            <goals>
                                <goal>dubbo-process-aot</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

运行命令(细节需参考 Dubbo 官网教程及配套示例):

mvn clean native:compile -P native -P native-dubbo -DskipTests

11、代码演示

https://gitee.com/noear/solon-examples/tree/main/7.Solon-Remoting-Rpc/demo7014-rpc_dubbo3_sml