Dubbo服务暴露过程中有涉及到调用ProxyFactory 中方法获取Invoker对象的过程,现在我们来深究下源码,来看下这个过程是在做些什么,返回的Invoker 对象是什么,我们来看一下代码的切入点:
Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
这里proxyFactory实在ServiceConfig中定义的静态常量,赋值后无法修改:
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
proxyFactory通过ExtensionLoader拓展机制进行加载。查看ProxyFactory接口源码如下:
/* * 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;import com.alibaba.dubbo.common.Constants;import com.alibaba.dubbo.common.URL;import com.alibaba.dubbo.common.extension.Adaptive;import com.alibaba.dubbo.common.extension.SPI;/** * ProxyFactory. (API/SPI, Singleton, ThreadSafe) * * @author william.liangf */@SPI("javassist")public interface ProxyFactory { /** * create proxy. * * @param invoker * @return proxy */ @Adaptive({Constants.PROXY_KEY})T getProxy(Invoker invoker) throws RpcException; /** * create invoker. * * @param * @param proxy * @param type * @param url * @return invoker */ @Adaptive({Constants.PROXY_KEY}) Invoker getInvoker(T proxy, Class type, URL url) throws RpcException;}
ProxyFactory接口有三个实现类,分别为JavassistProxyFactory、JdkProxyFactory、StubProxyFactoryWrapper。其中JavassistProxyFactory、JdkProxyFactory作为代理工厂,StubProxyFactoryWrapper实现了对代理工厂进行装饰的功能。在Dubbo中通过SPI配置默认的代理工厂为JavassistProxyFactory
接下来我们重点来看JavassistProxyFactory 代理工厂:
继承图如下:
JavassistProxyFactory 源码非常简单,只有两个方法:(代码调试的入参已经注释在源码中)
/* * 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.proxy.javassist;import com.alibaba.dubbo.common.URL;import com.alibaba.dubbo.common.bytecode.Proxy;import com.alibaba.dubbo.common.bytecode.Wrapper;import com.alibaba.dubbo.rpc.Invoker;import com.alibaba.dubbo.rpc.proxy.AbstractProxyFactory;import com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker;import com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler;/** * JavaassistRpcProxyFactory * * @author william.liangf */public class JavassistProxyFactory extends AbstractProxyFactory { @SuppressWarnings("unchecked") publicT getProxy(Invoker invoker, Class [] interfaces) { return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); } /** * * @param proxy DemoServiceImpl * @param type interface com.alibaba.dubbo.demo.DemoService * @param url injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&default.accepts=1000&default.threadpool=fixed&default.threads=100&default.timeout=5000&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&owner=uce&pid=9176&side=provider×tamp=1527927801444 * @param * @return */ public Invoker getInvoker(T proxy, Class type, URL url) { // TODO Wrapper类不能正确处理带$的类名 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); return new AbstractProxyInvoker (proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class [] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; }}
其中getProxy是实现抽象类AbstractProxyFactory中的抽象方法。AbstractProxyFactory抽象类实现了ProxyFactory接口中getProxy方法,JdkProxyFactory也实现了抽象类AbstractProxyFactory中的getProxy抽象方法。Javassist与Jdk动态代理的共同部分被封装在父类AbstractProxyFactory中,具体的实现类只需负责实现代理生成过程的差异化部分。
其中getInvoker方法是在ProxyFactory接口中定义的,用于创建Invoker。getInvoker中代码很简单,直接返回一个匿名类。匿名类继承了AbstractProxyInvoker抽象类,AbstractProxyInvoker抽象类又实现了Invoker接口,即表明该匿名类实现了Invoker接口,匿名类是封装了服务提供者的调用者。
Invoker接口定义了一个泛型。定义的方法很简单,只有两个方法,如下:
package com.alibaba.dubbo.rpc;import com.alibaba.dubbo.common.Node;public interface Invokerextends Node { //获取服务对象接口 Class getInterface(); //获取封装了服务的调用者 Result invoke(Invocation invocation) throws RpcException;}
抽象类AbstractProxyInvoker实现了Invoker接口,AbstractProxyInvoker定义属性和构造方法如下:
private final T proxy; private final Classtype; private final URL url; public AbstractProxyInvoker(T proxy, Class type, URL url) { if (proxy == null) { throw new IllegalArgumentException("proxy == null"); } if (type == null) { throw new IllegalArgumentException("interface == null"); } if (!type.isInstance(proxy)) { throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type); } this.proxy = proxy; this.type = type; this.url = url; }
- proxy:是final类型变量,指向服务提供者
- type:是final类型变量,服务的接口类型
- url:是final类型变量,携带服务地址、端口等多种信息的自定义URL对象
AbstractProxyInvoker也实现了invoker方法。方法内部很简单,直接通过RpcResult创建一个对象即可,创建RpcResult时的构建参数是通过方法doInvoke生成的。如下:
public Result invoke(Invocation invocation) throws RpcException { try { 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); } }
这里的doInvoke方法是抽象方法,由子类实现。抽象方法定义如下:
protected abstract Object doInvoke(T proxy, String methodName, Class [] parameterTypes, Object[] arguments) throws Throwable;
在ProxyFactory接口JavassistProxyFactory实现类中,getInvoker方法内部通过匿名内部类实现了doInvoke抽象方法。
Result接口主要定义了RPC 调用的相关方法,如下:
package com.alibaba.dubbo.rpc;import java.util.Map;public interface Result { Object getValue(); Throwable getException(); boolean hasException(); Object recreate() throws Throwable; @Deprecated Object getResult(); MapgetAttachments(); String getAttachment(String key); String getAttachment(String key, String defaultValue);}
RpcResult是对Result接口的一个实现。可看作对传入对象Object的一个包装,部分源码如下:
public class RpcResult implements Result, Serializable { private static final long serialVersionUID = -6925924956850004727L; private Object result; private Throwable exception; private Mapattachments = new HashMap (); public RpcResult() { } public RpcResult(Object result) { this.result = result; } public RpcResult(Throwable exception) { this.exception = exception; } public Object recreate() throws Throwable { if (exception != null) { throw exception; } return result; }}
这就是Dubbo服务发布的Invoker生成过程