Auto proxy & Auto scan HTTP RPC library

周末在家,闲来无事,就想写一个服务器端自动扫描并注册,客户端自动扫描并代理的 RPC 组件,基于 Spring; 整理了一下思路,这个组件分三个部分:coreserverclient;如下: http-rpc

分三个步骤完成: - core:服务定义,数据序列化方式; - server:服务类自动扫描并注册、服务暴露; - client:客户端接口自动扫描并代理;

第一步 core

  • 服务定义:一个服务狭义地理解为一个函数,这里面就包含函数的入参数和出参;另外一个层面的问题,怎么样定位服务呢?站在 Java 角度,我使用ServiceNamespaceServiceMapping两个注解,ServiceNamespace是一些同类服务的命名空间,ServiceMapping是具体服务入口;默认有一个 value 值,即为命名空间的名字和服务的名字;
  • 数据序列化方式:我这里选择了 ProtoStuff

下面贴出相关代码:

package io.http.rpc.core.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceNamespace {

    /**
     *
     * namespace of service
     *
     */
    String value() default "";

}
package io.http.rpc.core.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceMapping {

    /**
     *
     * name of service
     *
     */
    String value() default "";

}
package io.http.rpc.core;

public interface CoreServiceInvoker {

    /**
     * core service.
     * @param namespace 命名空间
     * @param name 服务名
     * @param parameters 参数列表
     *
     * */
    Object invoke(String namespace, String name, Object[] parameters);

}
package io.http.rpc.core.serialize;

import io.protostuff.LinkedBuffer;  
import io.protostuff.ProtobufIOUtil;  
import io.protostuff.Schema;  
import io.protostuff.runtime.RuntimeSchema;

/**
 * Created by manbu on 7/2/16.
 */
public final class ProtoSerializeUtils {

    @SuppressWarnings("unchecked")
    public static <T> byte[] encode(T object) {

        Schema<T> schema = RuntimeSchema.getSchema((Class<T>) object.getClass());

        LinkedBuffer buffer = LinkedBuffer.allocate(512);

        return ProtobufIOUtil.toByteArray(object, schema,  buffer);
    }

    @SuppressWarnings("unchecked")
    public static <T> T decode(byte[] data, Class<T> clazz) {

        Schema<T> schema = RuntimeSchema.getSchema(clazz);

        T m = schema.newMessage();

        ProtobufIOUtil.mergeFrom(data, m, schema);

        return m;
    }

}

第二步 server

  • 自动扫描:

通过io.http.rpc.server.auto.ServiceScannerConfigurer的配置basePackage,扫描逻辑借鉴 mybatis 的 Mapper 扫描机制,扩展org.springframework.context.annotation.ClassPathBeanDefinitionScanner

代码:

io.http.rpc.server.auto.ClassPathServiceScanner  
  • 服务注册:

『服务注册中心』即是一个 Service Holder,当扫描到ServiceNamespace即注册到『服务注册中心』中;

代码:

io.http.rpc.server.ServiceRegistrationCenter  
  • 服务暴露: 通过实现org.springframework.web.HttpRequestHandler来暴露服务,并在接收到请求后反序列化再从服务注册中心找到服务并执行;

代码:

io.http.rpc.server.HttpServiceExporter  

第三步 client

  • 自动扫描并代理

通过io.http.rpc.client.auto.ServiceScannerConfigurer的配置basePackage,扫描逻辑借鉴 mybatis 的 Mapper 扫描机制,扩展org.springframework.context.annotation.ClassPathBeanDefinitionScanner;扫描得到一个服务接口后,即通过改变 Spring Bean 的定义,使用ServiceFactoryBean生产出一个代理类;代理逻辑将请求交给核心层的 ProxyExecutor;

代码:

io.http.rpc.client.auto.ClassPathServiceScanner  
io.http.rpc.client.auto.ServiceScannerConfigurer  
io.http.rpc.client.auto.ServiceFactoryBean  
  • ClientBuilder

这里简单实现一个 ClientBuilder;仿照netty-rpc,后续再进行完善;

https://github.com/manbusky/http-rpc

漫步

A lazy programmer!