如何设计一款与MVC使用一模一样的RPC框架?

186 阅读1分钟

1. 目标

这是服务端提供的接口。

@RestController
@RequestMapping("user")
@Slf4j
public class UserController {


    @GetMapping("info")
    public User getUser(@RequestParam Long id) {
        log.info("getUser, id : {}", id);
        User user = new User();
        user.setId(id);
        user.setSex(1);
        user.setEmail("23132132@qq.com");
        user.setUsername("qyh");
        return user;
    }


    @PostMapping("save")
    public R saveUser(@RequestBody User user) {
        log.info("user : {}", user);
        return R.success(user);
    }
}

现在想要达成的效果是客户端只需要书写如下代码,就能成功调用服务端。

@FeignClient(url = "localhost:12345/user")
public interface UserClient {

    @GetMapping("info")
    User getUserById(@RequestParam("id") Long id);

    @PostMapping("save")
    R saveUser(@RequestBody User user);
}

我们可以发现,客户端代码和服务端代码长得一模一样,其他地方怎么调用呢?

@RestController
@RequestMapping("test")
public class TestController {

    final UserClient userClient;

    public TestController(UserClient userClient) {
        this.userClient = userClient;
    }

    @GetMapping("getUserById")
    public User getUserById(@RequestParam long id) {
        return userClient.getUserById(id);
    }

    @GetMapping("saveUser")
    public R saveUser(@RequestParam Map<String, Object> params) {
        String username = (String) params.get("username");
        Integer sex = Integer.parseInt((String) params.get("sex"));
        String email = (String) params.get("email");
        Long id = Long.parseLong((String) params.get("id"));

        User user = new User();
        user.setId(id);
        user.setUsername(username);
        user.setSex(sex);
        user.setEmail(email);

        return userClient.saveUser(user);
    }
}

这样就简化了一堆开发的代码。只需要赋值服务端的接口代码,然后就像调用本地方法一样调用远程方法。这就是RPC的精髓所在。

下面介绍一下设计该RPC框架的技术

2. 设计思路

2.1 factoryBean

factoryBean是spring提供构建复杂对象的技术,常见的框架例如mybatis整合spring,openFeign整合spring都是采用factoryBean来构建的。所以要完成这种用代理对象完成接口实现的套路。

2.2