Last active
March 16, 2018 07:18
-
-
Save qsLI/9180072a5751c8801f268c676a7a6baf to your computer and use it in GitHub Desktop.
泛化调用consumer端的实现逻辑
This file contains hidden or 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
/* | |
* Copyright 1999-2011 Alibaba Group. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.alibaba.dubbo.rpc.filter; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Method; | |
import com.alibaba.dubbo.common.Constants; | |
import com.alibaba.dubbo.common.extension.Activate; | |
import com.alibaba.dubbo.common.logger.Logger; | |
import com.alibaba.dubbo.common.logger.LoggerFactory; | |
import com.alibaba.dubbo.common.utils.PojoUtils; | |
import com.alibaba.dubbo.common.utils.ReflectUtils; | |
import com.alibaba.dubbo.rpc.Filter; | |
import com.alibaba.dubbo.rpc.Invocation; | |
import com.alibaba.dubbo.rpc.Invoker; | |
import com.alibaba.dubbo.rpc.Result; | |
import com.alibaba.dubbo.rpc.RpcException; | |
import com.alibaba.dubbo.rpc.RpcInvocation; | |
import com.alibaba.dubbo.rpc.RpcResult; | |
import com.alibaba.dubbo.rpc.service.GenericException; | |
import com.alibaba.dubbo.rpc.support.ProtocolUtils; | |
/** | |
* GenericImplInvokerFilter | |
* | |
* @author william.liangf | |
*/ | |
@Activate(group = Constants.CONSUMER, value = Constants.GENERIC_KEY, order = 20000) | |
public class GenericImplFilter implements Filter { | |
private static final Logger logger = LoggerFactory.getLogger(GenericImplFilter.class); | |
private static final Class<?>[] GENERIC_PARAMETER_TYPES = new Class<?>[] {String.class, String[].class, Object[].class}; | |
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { | |
String generic = invoker.getUrl().getParameter(Constants.GENERIC_KEY); | |
if (ProtocolUtils.isGeneric(generic) | |
&& ! Constants.$INVOKE.equals(invocation.getMethodName()) | |
&& invocation instanceof RpcInvocation) { // request | |
RpcInvocation invocation2 = (RpcInvocation) invocation; | |
String methodName = invocation2.getMethodName(); | |
Class<?>[] parameterTypes = invocation2.getParameterTypes(); | |
Object[] arguments = invocation2.getArguments(); | |
String[] types = new String[parameterTypes.length]; | |
for (int i = 0; i < parameterTypes.length; i ++) { | |
types[i] = ReflectUtils.getName(parameterTypes[i]); | |
} | |
Object[] args = PojoUtils.generalize(arguments); | |
// 这里设置调用的方法是$invoke, 将参数Map传给provider端 | |
invocation2.setMethodName(Constants.$INVOKE); | |
invocation2.setParameterTypes(GENERIC_PARAMETER_TYPES); | |
invocation2.setArguments(new Object[] {methodName, types, args}); | |
Result result = invoker.invoke(invocation2); | |
if (! result.hasException()) { | |
// provider端返回的是个HashMap | |
Object value = result.getValue(); | |
try { | |
Method method = invoker.getInterface().getMethod(methodName, parameterTypes); | |
// realize将包含对象属性的HashMap转成实际的对象 | |
return new RpcResult(PojoUtils.realize(value, method.getReturnType(), method.getGenericReturnType())); | |
} catch (NoSuchMethodException e) { | |
throw new RpcException(e.getMessage(), e); | |
} | |
} else if (result.getException() instanceof GenericException) { | |
GenericException exception = (GenericException) result.getException(); | |
try { | |
String className = exception.getExceptionClass(); | |
Class<?> clazz = ReflectUtils.forName(className); | |
Throwable targetException = null; | |
Throwable lastException = null; | |
try { | |
targetException = (Throwable) clazz.newInstance(); | |
} catch (Throwable e) { | |
lastException = e; | |
for (Constructor<?> constructor : clazz.getConstructors()) { | |
try { | |
targetException = (Throwable) constructor.newInstance(new Object[constructor.getParameterTypes().length]); | |
break; | |
} catch (Throwable e1) { | |
lastException = e1; | |
} | |
} | |
} | |
if (targetException != null) { | |
try { | |
Field field = Throwable.class.getDeclaredField("detailMessage"); | |
if (! field.isAccessible()) { | |
field.setAccessible(true); | |
} | |
field.set(targetException, exception.getExceptionMessage()); | |
} catch (Throwable e) { | |
logger.warn(e.getMessage(), e); | |
} | |
result = new RpcResult(targetException); | |
} else if (lastException != null) { | |
throw lastException; | |
} | |
} catch (Throwable e) { | |
throw new RpcException("Can not deserialize exception " + exception.getExceptionClass() + ", message: " + exception.getExceptionMessage(), e); | |
} | |
} | |
return result; | |
} // request | |
if (invocation.getMethodName().equals(Constants.$INVOKE) | |
&& invocation.getArguments() != null | |
&& invocation.getArguments().length == 3 | |
&& ProtocolUtils.isGeneric(generic)) { | |
if (ProtocolUtils.isJavaGenericSerialization(generic)) { | |
Object[] args = (Object[]) invocation.getArguments()[2]; | |
for (Object arg : args) { | |
if (!(byte[].class == arg.getClass())) { | |
error(arg.getClass().getName()); | |
} | |
} | |
} | |
((RpcInvocation)invocation).setAttachment( | |
Constants.GENERIC_KEY, invoker.getUrl().getParameter(Constants.GENERIC_KEY)); | |
} | |
return invoker.invoke(invocation); | |
} | |
private void error(String type) throws RpcException { | |
throw new RpcException( | |
new StringBuilder(32) | |
.append("Generic serialization [") | |
.append(Constants.GENERIC_SERIALIZATION_NATIVE_JAVA) | |
.append("] only support message type ") | |
.append(byte[].class) | |
.append(" and your message type is ") | |
.append(type).toString()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment