Skip to content

Instantly share code, notes, and snippets.

@yangl
Created August 16, 2013 09:00
Show Gist options
  • Save yangl/6248365 to your computer and use it in GitHub Desktop.
Save yangl/6248365 to your computer and use it in GitHub Desktop.
Dubbo多token拦截器实现, 为每个调用方配置一个token,方便统计每个调用方的调用次等数据及服务降级处理;
multiToken=com.jd.market.servicemanagement.token.MultiTokenFilter
package com.jd.market.servicemanagement.token;
import java.lang.reflect.Method;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.google.common.base.Strings;
import com.jd.market.servicemanagement.token.collect.JvmLocalData;
import com.jd.market.servicemanagement.token.common.Constants;
import com.jd.market.servicemanagement.token.common.DegradeTypeEnum;
import com.jd.market.servicemanagement.token.configinfo.MethodModel;
import com.jd.market.servicemanagement.token.configinfo.SystemModel;
import com.jd.market.servicemanagement.token.configinfo.TokenModel;
import com.jd.market.servicemanagement.token.degrade.DelegateDowngradeHandler;
import com.jd.market.servicemanagement.token.degrade.DowngradeContext;
import com.jd.market.servicemanagement.token.degrade.DowngradeHandler;
/**
* dubbo多token拦截器实现
*
* 为每个调用方配置一个token,方便统计每个调用方的调用次等数据
*
* @author YANGLiiN
* @date 13-4-25 上午10:46
*/
@Activate(group = {com.alibaba.dubbo.common.Constants.PROVIDER/*
* ,
* com.alibaba.dubbo
* .
* common.Constants
* .CONSUMER
*/}, value = "multiToken")
public class MultiTokenFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(MultiTokenFilter.class);
private static final DowngradeHandler handler = new DelegateDowngradeHandler();
// private static Map<String, Class> interfaceClazzMap = new
// WeakHashMap<String, Class>();
// private static Method getMethod(Invoker<?> invoker, Invocation inv)
// throws ClassNotFoundException, NoSuchMethodException {
// String interfaceName = invoker.getInterface().getName();
// Class interfaceClazz = interfaceClazzMap.get(interfaceName);
// if (interfaceClazz == null) {
// interfaceClazz = Class.forName(interfaceName);
// interfaceClazzMap.put(interfaceName, interfaceClazz);
// }
// return interfaceClazz.getMethod(inv.getMethodName(),
// inv.getParameterTypes());
// }
@Override
public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
// =======服务调用方========
if (RpcContext.getContext().isConsumerSide()) {
// do nothing
// 让调用方配置filter="SafTokenFilter",从而调用saf里边的SafTokenFilter设置jdtoken的值
// String key =
// BuildKeyUtils.getSafConfigKey(invoker.getUrl().getPath(),
// invoker.getUrl()
// .getParameter(Constants.VERSION_KEY),
// invoker.getUrl()
// .getParameter(Constants.GROUP_KEY));
//
// SAFReferenceConfig config =
// DubboRPCPacker.getReferConfigMap().get(key);
//
// if (config != null) {
// String consumerToken = config.getJdtoken();
// if ((ConfigUtils.isNotEmpty(consumerToken))) {
// inv.getAttachments().put(TOKEN_KEY, consumerToken);
// }
// }
} else if (RpcContext.getContext().isProviderSide()) {
// =======服务提供者========
// Map<String, String> attachments = inv.getAttachments();
// String providerToken = attachments == null ? null :
// attachments.get(TOKEN_KEY);
String consumerToken = inv.getAttachments().get(Constants.TOKEN_KEY);
if (Strings.isNullOrEmpty(consumerToken)
|| consumerToken.split(Constants.TOKEN_SPLIT).length != 2) {
this.makeInvalidTokenErr(invoker, inv);
}
String[] token = consumerToken.split(Constants.TOKEN_SPLIT);
String clientId = token[0];
String clientSecret = token[1];
TokenModel consumerTm = new TokenModel(clientId, clientSecret);
Class interfaceClazz = invoker.getInterface();
// 接口名
String interfaceName = interfaceClazz.getName();
// 方法名
// FIXME 方法名相同而参数不同的方法取到的方法名是一样的
String methodName = inv.getMethodName();
SystemModel conf = JvmLocalData.cache;
if (conf != null) {
Map<String, MethodModel> methods = conf.getMethods();
if (methods != null && !methods.isEmpty()) {
MethodModel methodModel = methods.get(interfaceName + "." + methodName);
// 只拦截在系统里注册过的接口方法
if (methodModel != null) {
Map<String, TokenModel> tokens = methodModel.getTokens();
// *************************************
// ************ token 处理 *************
// *************************************
// 1.系统没有注册token直接返回invalidToken
if (tokens == null || tokens.isEmpty()) {
this.makeInvalidTokenErr(invoker, inv);
}
// 2.验证token是否匹配
TokenModel providerTm = tokens.get(clientId);
if (providerTm == null || !providerTm.isMath(consumerTm)) {
this.makeInvalidTokenErr(invoker, inv);
}
// *************************************
// *************** 降级处理 *************
// *************************************
int status = methodModel.getStatus();
if (Constants.METHOD_RUNNING != status) {
DegradeTypeEnum degradeType = methodModel.getDegradeType();
DowngradeContext context = new DowngradeContext();
context.setContent(methodModel.getMockContent());
context.setDowngradeType(degradeType);
context.setId(methodModel.getMockMd5());
try {
Method method = interfaceClazz.getMethod(inv.getMethodName(),
inv.getParameterTypes());
Object objectRs = handler.handle(method, context);
return new RpcResult(objectRs);
}
catch (NoSuchMethodException e) {
// do nothing
}
}
}
}
}
}
return invoker.invoke(inv);
}
private void makeInvalidTokenErr(Invoker<?> invoker, Invocation inv) {
String err = "Invalid token! Forbid invoke remote service "
+ invoker.getInterface()
+ " method "
+ inv.getMethodName()
+ "() from consumer "
+ RpcContext.getContext().getRemoteAddress()
+ " to provider "
+ RpcContext.getContext().getLocalAddress();
logger.info("*******Invalid token*******[RPC-INFO:{}]", err);
throw new RpcException(err);
}
// private void makeThrowErr(Invoker<?> invoker, Invocation inv) {
// String err =
// "The remote service is running in degrade [throw exception] mode "
// + invoker.getInterface()
// + " method "
// + inv.getMethodName()
// + "() from consumer "
// + RpcContext.getContext().getRemoteAddress()
// + " to provider "
// + RpcContext.getContext().getLocalAddress();
//
// logger.info("*******Degrade [throw exception] mode*******[RPC-INFO:{}]",
// err);
// throw new RpcException(err);
//
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment