Created
August 16, 2013 09:00
-
-
Save yangl/6248365 to your computer and use it in GitHub Desktop.
Dubbo多token拦截器实现, 为每个调用方配置一个token,方便统计每个调用方的调用次等数据及服务降级处理;
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
multiToken=com.jd.market.servicemanagement.token.MultiTokenFilter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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