rpc系列2-提供上下文RpcContext

实现要求:提供RPC上下文,客户端可以透传数据给服务端。

一个应用的基本设计包含几个重要的角色:

  • 实体域
  • 会话域
  • 服务域

实体域就是应用中抽象出来的组件,如Spring中的Bean,Mybatis中的MappedStatement等。会话域代表着一次交互过程,如Mybatis中的SqlSession,而服务域就是组件的功能集,负责会话域和实体域的生命周期管理,如Spring的ApplicationContext,Shiro的SecurityManager等。

现在构造我们这个rpc demo中的会话域角色RpcContext。其主要职责就是负责在一次会话生命周期内,保存、传递相关参数数据。会话中的执行体就是线程了,那么理所应当的RpcContext就应该和当前执行线程绑定。很容易想到了ThreadLocal!

实现如下:

/**
 * rpc上下文
 * 
 * @author wqx
 *
 */
public class RpcContext {
    
    private static ThreadLocal<Map<String,Object>> context = new ThreadLocal<Map<String,Object> >(){
        @Override
        protected Map<String,Object> initialValue() {
            Map<String,Object> m = new HashMap<String,Object>();
            return m;
        }
    };
    
    public static void addAttribute(String key, Object value){
        context.get().put(key,value);
    }
    
    public static Object getAttribute(String key){
        return context.get().get(key);
    }
    
    public static Map<String,Object> getAttributes(){
        return Collections.unmodifiableMap(context.get());
    }
}

RpcContext中的数据传输载体还是选择RpcRequest,将其包在请求体中即可。如下:

public class RpcRequest implements Serializable
{
    /**
     * 
     */
    private static final long serialVersionUID = -7102839100899303105L;

    //方法名
    private String methodName;
    
    //参数类型
    private Class<?>[] parameterTypes;
    
    //参数列表
    private Object[] args;
    
    //参数
    private Map<String,Object> context;
    

RpcBuilder中在发送请求前,需要从当前上下文中获取数据。传入RpcRequest对象。如下:

RpcRequest request = new RpcRequest(method.getName(), method.getParameterTypes(),args,RpcContext.getAttributes());

同理,在服务端接收到请求对象RpcRequest之后,需要将RpcRequest中传来的数据和当前上下文进行关联。Handler的run方法修改如下:

        public void run() {
            try{
                ObjectInputStream in = null;
                ObjectOutputStream out = null;
                RpcResponse response = new RpcResponse();
                try {
                    in = new ObjectInputStream(socket.getInputStream());
                    out = new ObjectOutputStream(socket.getOutputStream());

                    Object req = in.readObject();
                    if(req instanceof RpcRequest){
                        RpcRequest rpcRequest = (RpcRequest)req;
                        //关联客户端传来的上下文数据
                        RpcContext.context.set(rpcRequest.getContext());
                        Method method = service.getClass().getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());
                        //。。。
        }

测试:

业务接口增加测试方法:
public interface UserService {
    
    /**
     * 上下文测试,透明传输数据
     */
    public Map<String,Object> rpcContextTest();
    
    //。。。
}
public class UserServiceImpl implements UserService {

    @Override
    public Map<String,Object> rpcContextTest() {
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("server","hahaha");
        if(RpcContext.getAttributes() != null )
            map.putAll(RpcContext.getAttributes());
        return map;
    }
    //。。。
}

客户端测试代码:

@Test
public void testRpcContext(){
    RpcContext.addAttribute("client","huhuhu");
    Map<String, Object> res = userService.rpcContextTest();
    Assert.assertEquals(res.get("server"),"hahaha");
    Assert.assertEquals(res.get("client"),"huhuhu");
}

完整代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转自:http://blog.csdn.net/kesonyk/article/details/50924489 ...
    晴天哥_王志阅读 25,031评论 2 38
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,355评论 19 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 13,852评论 6 13
  • 两周前回校,下火车,换乘地铁,出站时一对夫妇叫住了我,报出校名问我该搭什么公交。我转过头看向他们身后内向的学弟,说...
    墨舒朗阅读 2,999评论 0 0
  • 积极参与 乐在其中 锻炼身体 神心放松 景美花香 欢乐融融 汗流浃背 举足轻重 不虚此行 友情更浓 ----代西猛...
    云淑云卷阅读 3,902评论 3 2