在项目中转递参数通常是在接口中传递,然后在每个方法中接受这些参数处理。dubbo提供了rpc上下文可以实现设置和接受这些参数,实现我们的参数透传。(本文于2019年11在个人博客简书发表)
1.RpcContext
利用RpcContext实现consumer和provicer参数传递例如:
消费端: RpcContext.getContext().setAttachment("bizId", "小程序"); //调用dubbo activityAdminFacade.queryExchangeActivitiesByOption(option); 服务端: @Override public PageResult<ExchangeActivityDTO> queryExchangeActivitiesByOption(ActivityQueryOption option) { String userInfo = RpcContext.getContext().getAttachment("bizId"); }
实际上rpcContext也是用到了dubbo filter 特性。ConsumerContextFilter attachment中参数会直接带到invocation对象,传递至provider端。finaly中RpcContext.getContext().clearAttachments(); 每次调用会直接清除。所以需要我们每次调用dubbo服务接口前都要设置setAttachment。
@Activate(group = Constants.CONSUMER, order = -10000) public class ConsumerContextFilter implements Filter { public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { RpcContext.getContext() .setInvoker(invoker) .setInvocation(invocation) .setLocalAddress(NetUtils.getLocalHost(), 0) .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort()); if (invocation instanceof RpcInvocation) { ((RpcInvocation)invocation).setInvoker(invoker); } try { return invoker.invoke(invocation); } finally { RpcContext.getContext().clearAttachments(); } } }
2.有的时候我们不想每次调用dubbo接口都要去设置RpcContext。所以需要我们自己去实现定义一个dubbo filter。当然我们也可以直接修改源码哈哈(不推荐)
2.1 范围:一个线程上下文内
public class BizIdUtils { private static final ThreadLocal<String> Cache = new ThreadLocal<String>(); public static String getBizId() { return Cache.get(); } public static void setBizId(String bizId) { Cache.set(bizId); } public static void clear() { Cache.remove(); } }
package com.test.dubbo; public class TraceIdFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { String traceId = RpcContext.getContext().getAttachment("BizId"); if ( !StringUtils.isEmpty(BizId) ) { // *) 从RpcContext里获取bizId并保存 BizIdUtils.setBizId(bizId); } else { // *) 交互前重新设置traceId, 避免信息丢失 RpcContext.getContext().setAttachment("bizId", BizIdUtils.getBizId()); } // *) 实际的rpc调用 return invoker.invoke(invocation); } }
BizIdUtils ThreadLocal就是用来保存当前线程的变量值。所以在一个线程上下文中,只需要在第一次设置RpcContext.setAttachment即可。比如web的一次请求。
2.2 范围:设置整个consumer端
public class MyFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { RpcContext.getContext().setAttachment("bizId", "电商"); Result result = invoker.invoke(invocation); return result; } }
这样我们consumer端就不需再调用RpcContext了。
2.3 如何使filter生效
我们自定义filter的话,需要在resource下创建 /META-INFO/dubbo/com.alibaba.dubbo.rpc.Filter
文件内容为
helloFilter=com.fcbox.mall.item.MyFilter
helloFilter为自定义的名称
然后再application.properties中配置
springboot:spring.dubbo.consumer.filter=helloFilter
spring dubbo需要我们自己去实现java配置,这个filter就存放在DubboProperties中consumerConfig中filter中:
@Configuration @EnableConfigurationProperties(DubboProperties.class) public class DubboAutoConfiguration { @Autowired private DubboProperties dubboProperties; @Autowired private Environment environment; @Bean public ApplicationConfig requestApplicationConfig() { ApplicationConfig applicationConfig = dubboProperties.getApplication(); if(applicationConfig == null){ applicationConfig = new ApplicationConfig(); } return applicationConfig; } @Bean @Primary public RegistryConfig requestRegistryConfig() { RegistryConfig registryConfig = dubboProperties.getRegistry(); if(registryConfig == null){ registryConfig = new RegistryConfig(); } return registryConfig; } @Bean public ProtocolConfig requestProtocolConfig() { ProtocolConfig protocolConfig = dubboProperties.getProtocol(); if(protocolConfig == null){ protocolConfig = new ProtocolConfig(); } //获取启动参数,优先级最高 String host=environment.getProperty("server.address"); if(StringUtils.isNotEmpty(host)){ protocolConfig.setHost(host); } return protocolConfig; } @Bean public MonitorConfig requestMonitorConfig() { MonitorConfig monitorConfig = dubboProperties.getMonitor(); if(monitorConfig == null){ monitorConfig = new MonitorConfig(); } return monitorConfig; } @Bean public ProviderConfig requestProviderConfig(){ ProviderConfig providerConfig = dubboProperties.getProvider(); if(providerConfig == null){ providerConfig = new ProviderConfig(); } return providerConfig; } @Bean public ModuleConfig requestModuleConfig(){ ModuleConfig moduleConfig = dubboProperties.getModule(); if(moduleConfig == null){ moduleConfig = new ModuleConfig(); } return moduleConfig; } @Bean public MethodConfig requestMethodConfig(){ MethodConfig methodConfig = dubboProperties.getMethod(); if(methodConfig == null){ methodConfig = new MethodConfig(); } return methodConfig; } @Bean public ConsumerConfig requestConsumerConfig(){ ConsumerConfig consumerConfig = dubboProperties.getConsumer(); if(consumerConfig == null){ consumerConfig = new ConsumerConfig(); } return consumerConfig; } } public class DubboProperties { private String scan; private ApplicationConfig application; private RegistryConfig registry; private ProtocolConfig protocol; private MonitorConfig monitor; private ProviderConfig provider; private ModuleConfig module; private MethodConfig method; private ConsumerConfig consumer;
consumer配置类:com.alibaba.dubbo.config.ConsumerConfig