image.png
本節(jié)介紹 Dubbo 十層架構(gòu)中的 Proxy 層。
image.png
- ProxyFactory:代理工廠接口;
- StubProxyFactoryWrapper:代理工廠裝飾類(封裝了對
stub和local的處理邏輯),會在獲取ProxyFactory具體子類時進行 AOP;- AbstractProxyFactory:代理工廠模板類(封裝了獲取組裝接口的功能,用于創(chuàng)建動態(tài)代理),提供了模板方法;
- JavassistProxyFactory:基于 Javassist 實現(xiàn)的代理工廠;
- JdkProxyFactory:基于 JDK 動態(tài)代理實現(xiàn)的代理工廠;
- AbstractProxyInvoker:最終封裝的代理 Invoker,其子類內(nèi)部發(fā)起真正的調(diào)用;
- InvokerInvocationHandler:Proxy 發(fā)起調(diào)用時,會調(diào)用該類的 invoke(...),在該 invoke(...) 方法中,默認會調(diào)用
MockClusterInvoker的 invoke(...),之后一路進行調(diào)用。
一、代理工廠接口 ProxyFactory
@SPI("javassist")
public interface ProxyFactory {
/**
* 使用端:consumer
*
* 創(chuàng)造一個代理,用于服務引用創(chuàng)建代理
* @param invoker會被proxy調(diào)用的第一層Invoker,默認是 MockClusterInvoker
* @return proxy 代理對象
*/
@Adaptive({Constants.PROXY_KEY})
<T> T getProxy(Invoker<T> invoker) throws RpcException;
/**
* 使用端:provider
*
* 創(chuàng)建一個Invoker,默認是代理Invoker -- AbstractProxyInvoker 的子類對象
* @param <T> 接口 eg. com.alibaba.dubbo.demo.DemoService
* @param proxy ref實例, eg. emoServiceImpl實例
* @param type interface eg. com.alibaba.dubbo.demo.DemoService
* @param url --
* injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true...
* registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider...&export=dubbo://10.213.11.98:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true...
* @return invoker,默認是代理Invoker -- AbstractProxyInvoker 的子類對象
*/
@Adaptive({Constants.PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
二、代理工廠裝飾類 StubProxyFactoryWrapper
public class StubProxyFactoryWrapper implements ProxyFactory {
// 真正的ProxyFactory具體子類(JavassistProxyFactory/JdkProxyFactory)
private final ProxyFactory proxyFactory;
// 具有父類SPI接口(ProxyFactory)的單參構(gòu)造器,所以該類是一個Wrapper類,會在getExtension獲取ProxyFactory具體子類時進行aop
public StubProxyFactoryWrapper(ProxyFactory proxyFactory) {
this.proxyFactory = proxyFactory;
}
/**
* 使用端:consumer
*/
@Override
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
// 1. 調(diào)用 ProxyFactory 獲取代理
T proxy = proxyFactory.getProxy(invoker);
// 2. 如果不是泛化接口,處理 stub 和 local
...
return proxy;
}
/**
* 使用端:provider
*/
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
return proxyFactory.getInvoker(proxy, type, url);
}
}
三、代理工廠模板類 AbstractProxyFactory
public abstract class AbstractProxyFactory implements ProxyFactory {
@Override
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
/**
* 1. 構(gòu)造接口參數(shù),默認只有 invoker.getInterface()(eg. DemoService), EchoService.class 兩個接口
*/
...
Class<?>[] interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
...
/**
* 2. 調(diào)用子類的實現(xiàn)去創(chuàng)建代理
*/
return getProxy(invoker, interfaces);
}
/**
* 提供給子類的抽象方法
*/
public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);
}
四、JdkProxyFactory
public class JdkProxyFactory extends AbstractProxyFactory {
// 使用端:consumer
@Override
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
// 使用JDK方式創(chuàng)建Java動態(tài)代理,創(chuàng)建了動態(tài)代理的邏輯處理類 InvokerInvocationHandler,并且傳入了 MockClusterInvoker
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}
// 使用端:provider
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// 創(chuàng)建真正的Invoker代理
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
// 獲取真正的方法Method,proxy=DemoServiceImpl實例
Method method = proxy.getClass().getMethod(methodName, parameterTypes);
// 執(zhí)行真正的方法
return method.invoke(proxy, arguments);
}
};
}
}
五、JavassistProxyFactory
public class JavassistProxyFactory extends AbstractProxyFactory {
// 使用端:consumer
@Override
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
// 使用 com.alibaba.dubbo.common.bytecode.Proxy 創(chuàng)建代理,創(chuàng)建了動態(tài)代理的邏輯處理類 InvokerInvocationHandler,并且傳入了 MockClusterInvoker
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
// 使用端:provider
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// wrapper:通過動態(tài)生成一個真實的服務提供者(DemoServiceImpl)的wrapper類,來避免反射調(diào)用
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass());
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
// 直接調(diào)用wrapper,wrapper底層調(diào)用DemoServiceImpl
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
}
首先來看下 consumer 端:
Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))
這里首先調(diào)用 Proxy.getProxy(interfaces) 獲取到一個創(chuàng)建代理的工廠類 com.alibaba.dubbo.common.bytecode.Proxy0,如下:
package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.bytecode.Proxy;
import com.alibaba.dubbo.common.bytecode.proxy0;
import java.lang.reflect.InvocationHandler;
public class Proxy0 extends Proxy implements ClassGenerator.DC {
public Object newInstance(InvocationHandler invocationHandler) {
return new proxy0(invocationHandler);
}
}
之后調(diào)用了 Proxy0#newInstance 方法,創(chuàng)建了一個 com.alibaba.dubbo.common.bytecode.proxy0 實例,該實例就是最終的 DemoService 的代理對象。
DemoService demoService = (DemoService) context.getBean("demoService");
這里的 demoService 就是上述的 com.alibaba.dubbo.common.bytecode.proxy0 實例。
package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.demo.DemoService;
import com.alibaba.dubbo.rpc.service.EchoService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class proxy0 implements EchoService, DemoService {
public static Method[] methods;
private InvocationHandler handler;
public String sayHello(String string) {
Object[] arrobject = new Object[]{string};
Object object = this.handler.invoke(this, methods[0], arrobject);
return (String)object;
}
public Object $echo(Object object) {
Object[] arrobject = new Object[]{object};
Object object2 = this.handler.invoke(this, methods[1], arrobject);
return object2;
}
public proxy0() {
}
public proxy0(InvocationHandler invocationHandler) {
this.handler = invocationHandler;
}
}
- proxy0 實現(xiàn)的接口就是 AbstractProxyFactory 中獲取的接口;
- 當調(diào)用
proxy0#sayHello時,實際上其內(nèi)部執(zhí)行的是InvokerInvocationHandlerr#invoke,來看一下 InvokerInvocationHandler。
六、代理邏輯處理類 InvokerInvocationHandler
public class InvokerInvocationHandler implements InvocationHandler {
/**
* 第一個被Proxy調(diào)用的Invoker,默認為MockClusterInvoker
*/
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
// 1. 創(chuàng)建請求參數(shù)RpcInvocation
// 2. 執(zhí)行調(diào)用
// 3. 對調(diào)用結(jié)果進行重建recreate():若響應有異常,直接拋異常;否則返回響應
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}
七、Invoker代理 AbstractProxyInvoker
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
// 真實對象 ref, eg. DemoServiceImpl
private final T proxy;
// 接口類型,eg. DemoService
private final Class<T> type;
...
public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
...
this.proxy = proxy;
this.type = type;
...
}
...
/**
* 進行調(diào)用
* @param invocation 請求參數(shù)
* @return 返回結(jié)果
* @throws RpcException
*/
@Override
public Result invoke(Invocation invocation) throws RpcException {
try {
// 1. 調(diào)用子類發(fā)起請求
// 2. 包裝響應為 RpcResult
return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
} catch (InvocationTargetException e) {
return new RpcResult(e.getTargetException());
} catch (Throwable e) {
throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
// 子類覆寫的真正調(diào)用的方法
protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;
}
AbstractProxyInvoker 的子類在 JdkProxyFactory#getInvoker(...) 和 JavassistProxyFactory#getInvoker(...) 中進行創(chuàng)建的,來看下JavassistProxyFactory#getInvoker(...) :
// 使用端:provider
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// wrapper:通過動態(tài)生成一個真實的服務提供者(DemoServiceImpl)的wrapper類,來避免反射調(diào)用
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass());
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
// 直接調(diào)用wrapper,wrapper底層調(diào)用DemoServiceImpl
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
再貼下最終生成的 wrapper 類實例(com.alibaba.dubbo.common.bytecode.Wrapper0)。
package com.alibaba.dubbo.common.bytecode;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.bytecode.NoSuchMethodException;
import com.alibaba.dubbo.common.bytecode.NoSuchPropertyException;
import com.alibaba.dubbo.common.bytecode.Wrapper;
import com.alibaba.dubbo.demo.DemoService;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class Wrapper0 extends Wrapper implements ClassGenerator.DC {
...
/**
* @param object 實現(xiàn)類ref,eg. DemoServiceImpl
* @param string 方法名稱
* @param arrclass 參數(shù)類型
* @param arrobject 參數(shù)值
* @return 調(diào)用返回值
* @throws java.lang.reflect.InvocationTargetException
*/
public Object invokeMethod(Object object, String string, Class[] arrclass, Object[] arrobject) throws InvocationTargetException {
DemoService demoService;
try {
demoService = (DemoService)object;
} catch (Throwable throwable) {
throw new IllegalArgumentException(throwable);
}
try {
if ("sayHello".equals(string) && arrclass.length == 1) {
return demoService.sayHello((String)arrobject[0]);
}
} catch (Throwable throwable) {
throw new InvocationTargetException(throwable);
}
throw new NoSuchMethodException(new StringBuffer().append("Not found method \"").append(string).append("\" in class com.alibaba.dubbo.demo.DemoService.").toString());
}
...
}

