Solon v4.1.0

Solon Rpc 应用开发 - 跑通第一次调用

</> markdown
2026年9月14日 上午5:09:42

Solon Rpc 应用通常拆成三部分:双方共享的服务接口、服务端实现、客户端消费方。体验与 Dubbo 相似。

1、 三个部分(模块)的职责

推荐把项目拆成:

user-api       共享接口和 DTO
user-provider  Solon 服务端,实现接口
user-consumer  Solon 客户端,调用接口

客户端只依赖 user-api 和 RPC 客户端依赖,不要把服务端数据库、Web 容器实现传递给客户端。

2、 共享接口和 DTO

package demo.api;

import java.io.Serializable;

public interface UserService {
    User getById(long userId);
    void add(User user);
}

public class User implements Serializable {
    private long userId;
    private String name;
    private int level;

    public long getUserId() { return userId; }
    public void setUserId(long userId) { this.userId = userId; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getLevel() { return level; }
    public void setLevel(int level) { this.level = level; }
}

Serializable 对多种序列化方案更稳妥;如果明确只使用 JSON,DTO 通常不要求实现它。示例不用 Lombok,避免读者还要额外寻找 Lombok 依赖。

3、 服务端

服务端依赖 org.noear:solon-web。当前仓库的 solon-web shortcut 默认组合用了 snack4 序列化插件。

package demo.provider;

import demo.api.User;
import demo.api.UserService;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Remoting;

@Remoting
@Mapping("/rpc/v1/user")
public class UserServiceImpl implements UserService {
    @Override
    public User getById(long userId) {
        User user = new User();
        user.setUserId(userId);
        user.setName("demo");
        user.setLevel(1);
        return user;
    }

    @Override
    public void add(User user) {
        // 实际项目中在这里调用 service/repository
    }
}

@Mapping 是远程入口路径;@Remoting 表明这是远程服务。

入口和配置:

import org.noear.solon.Solon;

public class ProviderApp {
    public static void main(String[] args) {
        Solon.start(ProviderApp.class, args);
    }
}
# provider/src/main/resources/app.yml
server.port: 9001
solon.app:
  group: demo
  name: userapi

4、 客户端

客户端依赖共享接口,以及当前仓库中的 org.noear:namiorg.noear:nami-channel-httporg.noear:nami-coder-snack4。在 Solon Bean 中注入代理:

package demo.consumer;

import demo.api.User;
import demo.api.UserService;
import org.noear.nami.annotation.NamiClient;
import org.noear.nami.common.ContentTypes;
import org.noear.solon.annotation.Component;

@Component
public class UserCaller {
    @NamiClient(url = "http://localhost:9001/rpc/v1/user", headers = ContentTypes.JSON)
    private UserService userService;

    public User load(long id) {
        return userService.getById(id);
    }
}

@NamiClient 支持标在接口和字段上;在 Solon 中标在字段上时由 Nami 插件注入代理。接口必须是 interface,Builder 最终也只为接口创建 JDK Proxy。

客户端如果也启动 Web 服务,使用不同端口:

server.port: 8081
solon.app:
  group: demo
  name: userconsumer

5、 验证调用链

  1. 启动 provider,确认 9001 没有端口冲突。
  2. 启动 consumer。
  3. 调用 userService.getById(1)
  4. 若失败,先把问题限定在固定 URL;不要马上加入注册中心。

一次调用的关键对应关系:

客户端服务端
url/rpc/v1/user类上的 @Mapping
方法名 getById服务端接口实现方法
headers = ContentTypes.JSON服务端的 snack4/JSON 序列化支持
返回类型 User服务端返回的 DTO