你知道的越多,不知道的也越多!
基于现在的微服务架构,一个系统背后可能是几十个service去做支撑。那如何在多个服务间传递值呢?
场景描述:
一个用户下单某个商品,中间涉及到的服务有 (1)网关service -> (2)某个业务service -> (3)订单中心service -> (4)支付中心service…
这几个服务其实都需要用到用户身份。
首先网关service需要完成 用户身份校验的工作,当解析出用户信息的时候,如何传递到下游服务呢?
- 不可能说用参数形式吧?
因为这样会显得参数过于冗长。这里只是用户身份,那如果是一些请求头里的信息,比如记录了客户端发送的版本号和请求来源渠道呢?肯定不建议这种方式。
而且对日后的拓展也不好,参数Model的修改会引发Jar包的升级。
这里就可以使用Dubbo的Filter机制啦,终于可以讲重点了~
自己随手写了一个Filter,大致步骤如下:
- 写一个类去实现
org.apache.dubbo.rpc.Filter
,并重写里面的Invoke方法; - 项目META-INF/dubbo里新建一个文件,文件名=
org.apache.dubbo.rpc.Filter
,文件内容为key=value的形式,key随便写,value为上面的实现类的全路径。 - 最后将项目打包,让需要使用该过滤器的项目pom即可生效。
关键代码: 消费端和提供端都进行过滤。
package com.yuki.dubbo.zdy.filter;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义dubbo的过滤器
*/
//作用于消费者和提供者
@Activate(group = {CommonConstants.CONSUMER, CommonConstants.PROVIDER})
public class MyFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
long start = System.currentTimeMillis();
try {
dealContextParam(RpcContext.getContext());
return invoker.invoke(invocation);
} finally {
System.out.println("过滤器统计耗时:" + (System.currentTimeMillis() - start) + "ms");
}
}
/**
* 处理rpc调用上下文里的参数
*
* @param rpcContext
*/
public void dealContextParam(RpcContext rpcContext) {
//消费者端进行存值
if (RpcContext.getContext().isConsumerSide()) {
Map<String, String> data = new HashMap<>();
data.put("userId", "123456");
data.put("userName", "我是一个小小Yuki啊啊啊");
rpcContext.setAttachments(data);
} else {
//提供者取值,然后可以存入到全局变量中供使用,例如ThreadLocal<xx>
Map<String, String> attachments = rpcContext.getAttachments();
System.out.println("提供者拿到的参数:" + attachments);
}
}
}
运行结果:
核心类:RpcContext
可以使用RpcContext.getContext().isConsumerSide()
和RpcContext.getContext().isProviderSide()
可以很好的区分当前引入的项目是消费端还是提供端。
思考: 之前对Dubbo不是很了解,一直以为Filter只能作用在消费端,可用来做日志处理,或者耗时统计等。最近看了它的分层图,猛然发现两端都有个Filter。并且消费端和提供端最终处理都会经过Invoker。