dubbo组成原理-service服务调用

上一篇介绍了service的服务暴露,这里当然也要介绍一下服务的调用。正所谓好事成双


通过reference的标签,我们在dubbo的jar中找到DubboNamespaceHandler类中的ReferenceBean.class。这就是我们的切入点

registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));

众所周知,dubbo在使用RPC远程服务的时候,只需要配置简单reference标签,就可以像调用本地bean对象一样调用各自方法。这个bean对象就是代理工厂生产的代理对象。


FactoryBean:以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的Id从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身

ReferenceBean 实现了getObject() 调用get(),调用init() 

 private void init() {
	    if (initialized) {
	        return;
	    }
	    initialized = true;
    	if (interfaceName == null || interfaceName.length() == 0) {
    	    throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
    	}
    	// 获取消费者全局配置
    	checkDefault();
        appendProperties(this);
        if (getGeneric() == null && getConsumer() != null) {
            setGeneric(getConsumer().getGeneric());
        }
        if (ProtocolUtils.isGeneric(getGeneric())) {
            interfaceClass = GenericService.class;
        } else {
            try {
				interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
				        .getContextClassLoader());
			} catch (ClassNotFoundException e) {
				throw new IllegalStateException(e.getMessage(), e);
			}
            checkInterfaceAndMethods(interfaceClass, methods);
        }
        String resolve = System.getProperty(interfaceName);
        String resolveFile = null;
        if (resolve == null || resolve.length() == 0) {
	        resolveFile = System.getProperty("dubbo.resolve.file");
	        if (resolveFile == null || resolveFile.length() == 0) {
	        	File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties");
	        	if (userResolveFile.exists()) {
	        		resolveFile = userResolveFile.getAbsolutePath();
	        	}
	        }
	        if (resolveFile != null && resolveFile.length() > 0) {
	        	Properties properties = new Properties();
	        	FileInputStream fis = null;
	        	try {
	        	    fis = new FileInputStream(new File(resolveFile));
					properties.load(fis);
				} catch (IOException e) {
					throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e);
				} finally {
				    try {
                        if(null != fis) fis.close();
                    } catch (IOException e) {
                        logger.warn(e.getMessage(), e);
                    }
				}
	        	resolve = properties.getProperty(interfaceName);
	        }
        }
        if (resolve != null && resolve.length() > 0) {
        	url = resolve;
        	if (logger.isWarnEnabled()) {
        		if (resolveFile != null && resolveFile.length() > 0) {
        			logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service.");
        		} else {
        			logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service.");
        		}
    		}
        }
        if (consumer != null) {
            if (application == null) {
                application = consumer.getApplication();
            }
            if (module == null) {
                module = consumer.getModule();
            }
            if (registries == null) {
                registries = consumer.getRegistries();
            }
            if (monitor == null) {
                monitor = consumer.getMonitor();
            }
        }
        if (module != null) {
            if (registries == null) {
                registries = module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
        if (application != null) {
            if (registries == null) {
                registries = application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
        checkApplication();
        checkStubAndMock(interfaceClass);
        Map<String, String> map = new HashMap<String, String>();
        Map<Object, Object> attributes = new HashMap<Object, Object>();
        map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE);
        map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
        map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
        if (ConfigUtils.getPid() > 0) {
            map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
        }
        if (! isGeneric()) {
            String revision = Version.getVersion(interfaceClass, version);
            if (revision != null && revision.length() > 0) {
                map.put("revision", revision);
            }

            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
            if(methods.length == 0) {
                logger.warn("NO method found in service interface " + interfaceClass.getName());
                map.put("methods", Constants.ANY_VALUE);
            }
            else {
                map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
            }
        }
        map.put(Constants.INTERFACE_KEY, interfaceName);
        appendParameters(map, application);
        appendParameters(map, module);
        appendParameters(map, consumer, Constants.DEFAULT_KEY);
        appendParameters(map, this);
        String prifix = StringUtils.getServiceKey(map);
        if (methods != null && methods.size() > 0) {
            for (MethodConfig method : methods) {
                appendParameters(map, method, method.getName());
                String retryKey = method.getName() + ".retry";
                if (map.containsKey(retryKey)) {
                    String retryValue = map.remove(retryKey);
                    if ("false".equals(retryValue)) {
                        map.put(method.getName() + ".retries", "0");
                    }
                }
                appendAttributes(attributes, method, prifix + "." + method.getName());
                checkAndConvertImplicitConfig(method, map, attributes);
            }
        }
        //attributes通过系统context进行存储.
        StaticContext.getSystemContext().putAll(attributes);
        ref = createProxy(map);
    }

最后通过createProxy获取的ref就是代理对象。

jdk的动态代理需要实现InvocationHandler接口的invoke方法。

将方法名方法参数传入InvokerInvocationHandler的invoke方

对于Object中的方法toString, hashCode, equals直接调用invoker的对应方法,

远程调用层是以Invocation, Result为中心, 这里根据要调用的方法以及传入的参数构建RpcInvocation对象,作为Invoker的入参



结合Invoker创建流程,我们知道此处的invoker为com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker,对应的invoke方法:

public Result invoke(Invocation invocation) throws RpcException {  
    Result result = null;  
        // 查询mock值,查询顺序methodName[sayHello].mock -> mock -> default.mock, 默认为false,即不进行mock  
        String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();   
        if (value.length() == 0 || value.equalsIgnoreCase("false")){  
            // 不进行mock的话直接调用后面的invoker  
            result = this.invoker.invoke(invocation);  
        } else if (value.startsWith("force")) {  
            if (logger.isWarnEnabled()) {  
                logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " +  directory.getUrl());  
            }  
            //如果值为force,表示强制mock,即不访问远端方法,直接调用mock数据  
            result = doMockInvoke(invocation, null);  
        } else {  
            // 其他的值,则是先调用后面的invoker,如果失败且不是业务错误时使用mock数据,  
                // 非业务错误包含:网络错误、超时错误、禁止访问错误、序列化错误及其他未知的错误,  
                // 业务错误则是接口实现类中的方法抛出的错误,如sayHello调用时产生异常  
               try {  
                result = this.invoker.invoke(invocation);  
            }catch (RpcException e) {  
                if (e.isBiz()) {  
                    throw e;  
                } else {  
                    if (logger.isWarnEnabled()) {  
                        logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " +  directory.getUrl(), e);  
                    }  
                    result = doMockInvoke(invocation, e);  
                }  
            }  
        }  
        return result;  
}  


mock支持的配置方式包含多种,这里就不一一说明了。有兴趣的可以通过官方网址深入了解

MockInvoker的invoke方法:

public Result invoke(Invocation invocation) throws RpcException {
    	String mock = getUrl().getParameter(invocation.getMethodName()+"."+Constants.MOCK_KEY);
    	if (invocation instanceof RpcInvocation) {
    		((RpcInvocation) invocation).setInvoker(this);
    	}
    	if (StringUtils.isBlank(mock)){
    		mock = getUrl().getParameter(Constants.MOCK_KEY);
    	}
    	
    	if (StringUtils.isBlank(mock)){
    		throw new RpcException(new IllegalAccessException("mock can not be null. url :" + url));
    	}
        mock = normallizeMock(URL.decode(mock));
        if (Constants.RETURN_PREFIX.trim().equalsIgnoreCase(mock.trim())){
        	RpcResult result = new RpcResult();
        	result.setValue(null);
        	return result;
        } else if (mock.startsWith(Constants.RETURN_PREFIX)) {
            mock = mock.substring(Constants.RETURN_PREFIX.length()).trim();
            mock = mock.replace('`', '"');
            try {
                Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
                Object value = parseMockValue(mock, returnTypes);
                return new RpcResult(value);
            } catch (Exception ew) {
            	throw new RpcException("mock return invoke error. method :" + invocation.getMethodName() + ", mock:" + mock + ", url: "+ url , ew);
            }
        } else if (mock.startsWith(Constants.THROW_PREFIX)) {
        	mock = mock.substring(Constants.THROW_PREFIX.length()).trim();
            mock = mock.replace('`', '"');
            if (StringUtils.isBlank(mock)){
            	throw new RpcException(" mocked exception for Service degradation. ");
            } else { //用户自定义类
            	Throwable t = getThrowable(mock);
				throw new RpcException(RpcException.BIZ_EXCEPTION, t);
            }
        } else { //impl mock
             try {
                 Invoker<T> invoker = getInvoker(mock);
                 return invoker.invoke(invocation);
             } catch (Throwable t) {
                 throw new RpcException("Failed to create mock implemention class " + mock , t);
             }
        }
    }

跟进getInvoker(mock)

 
  1.  private Invoker<T> getInvoker(String mockService){  
  2.               // Invoker由反射生成,需要缓存生成的Invoker(否则效率低)  
  3.         Invoker<T> invoker =(Invoker<T>) mocks.get(mockService);  
  4.         if (invoker != null ){  
  5.             return invoker;  
  6.         } else {  
  7.                        // 如果配置为默认,则mock类为原类名+Mock,如com.alibaba.dubbo.demo.DemoService的mock类为com.alibaba.dubbo.demo.DemoServiceMock   
  8.                        // 如果非默认配置,则按照配置的字符串创建类  
  9.                 Class<T> serviceType = (Class<T>)ReflectUtils.forName(url.getServiceInterface());  
  10.             if (ConfigUtils.isDefault(mockService)) {  
  11.                 mockService = serviceType.getName() + "Mock";  
  12.             }  
  13.             // 创建mock类并判断mock类是否是原类的子类  
  14.             Class<?> mockClass = ReflectUtils.forName(mockService);  
  15.             if (! serviceType.isAssignableFrom(mockClass)) {  
  16.                 throw new IllegalArgumentException("The mock implemention class " + mockClass.getName() + " not implement interface " + serviceType.getName());  
  17.             }  
  18.               // 这里copy的,应该是作者写重复了  
  19.             if (! serviceType.isAssignableFrom(mockClass)) {  
  20.                 throw new IllegalArgumentException("The mock implemention class " + mockClass.getName() + " not implement interface " + serviceType.getName());  
  21.             }  
  22.             try {  
  23.                                // 创建实例,并创建对应的代理  
  24.                 T mockObject = (T) mockClass.newInstance();  
  25.                 invoker = proxyFactory.getInvoker(mockObject, (Class<T>)serviceType, url);  
  26.                                // 只缓存10000个Invoker  
  27.                 if (mocks.size() < 10000) {  
  28.                     mocks.put(mockService, invoker);  
  29.                 }  
  30.                 return invoker;  
  31.             } catch (InstantiationException e) {  
  32.                 throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implemention class " + mockClass.getName(), e);  
  33.             } catch (IllegalAccessException e) {  
  34.                 throw new IllegalStateException(e);  
  35.             }  
  36.         }  
  37.     }  

紧接着 FailoverClusterInvoker调用策略

通过目录服务查找到所有订阅的服务提供者的Invoker对象

路由服务根据策略来过滤选择调用的Invokers

通过负载均衡策略LoadBalance来选择一个Invoker


public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {


    private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class);


    public FailoverClusterInvoker(Directory<T> directory) {
        super(directory);
    }


    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
    	List<Invoker<T>> copyinvokers = invokers;
    	checkInvokers(copyinvokers, invocation);
        int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
        if (len <= 0) {
            len = 1;
        }
        // retry loop.
        RpcException le = null; // last exception.
        List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers.
        Set<String> providers = new HashSet<String>(len);
        for (int i = 0; i < len; i++) {
        	//重试时,进行重新选择,避免重试时invoker列表已发生变化.
        	//注意:如果列表发生了变化,那么invoked判断会失效,因为invoker示例已经改变
        	if (i > 0) {
        		checkWheatherDestoried();
        		copyinvokers = list(invocation);
        		//重新检查一下
        		checkInvokers(copyinvokers, invocation);
        	}
            Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
            invoked.add(invoker);
            RpcContext.getContext().setInvokers((List)invoked);
            try {
                Result result = invoker.invoke(invocation);
                if (le != null && logger.isWarnEnabled()) {
                    logger.warn("Although retry the method " + invocation.getMethodName()
                            + " in the service " + getInterface().getName()
                            + " was successful by the provider " + invoker.getUrl().getAddress()
                            + ", but there have been failed providers " + providers 
                            + " (" + providers.size() + "/" + copyinvokers.size()
                            + ") from the registry " + directory.getUrl().getAddress()
                            + " on the consumer " + NetUtils.getLocalHost()
                            + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                            + le.getMessage(), le);
                }
                return result;
            } catch (RpcException e) {
                if (e.isBiz()) { // biz exception.
                    throw e;
                }
                le = e;
            } catch (Throwable e) {
                le = new RpcException(e.getMessage(), e);
            } finally {
                providers.add(invoker.getUrl().getAddress());
            }
        }
        throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method "
                + invocation.getMethodName() + " in the service " + getInterface().getName() 
                + ". Tried " + len + " times of the providers " + providers 
                + " (" + providers.size() + "/" + copyinvokers.size() 
                + ") from the registry " + directory.getUrl().getAddress()
                + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
                + Version.getVersion() + ". Last error is: "
                + (le != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le);
    }


}

执行选择的Invoker.inoker(invocation)

经过监听器链,默认没有

经过过滤器链,内置实现了很多

执行到远程调用的DubboInvoker

而 DubboInvoker

根据url 也就是根据服务提供者的长连接,这里封装成交互层对象ExchangeClient供这里调用

判断远程调用类型同步,异步还是oneway模式

ExchangeClient发起远程调用,底层remoting不在这里描述了

获取调用结果:

        Oneway返回空RpcResult

        异步,直接返回空RpcResult, ResponseFuture回调

        同步, ResponseFuture模式同步转异步,等待响应返回

DubboInvoker中的doInvoke

 @Override
    protected Result doInvoke(final Invocation invocation) throws Throwable {
        RpcInvocation inv = (RpcInvocation) invocation;
        final String methodName = RpcUtils.getMethodName(invocation);
        inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
        inv.setAttachment(Constants.VERSION_KEY, version);
        
        ExchangeClient currentClient;
        if (clients.length == 1) {
            currentClient = clients[0];
        } else {
            currentClient = clients[index.getAndIncrement() % clients.length];
        }
        try {
            boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
            boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
            int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT);
            if (isOneway) {
            	boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
                currentClient.send(inv, isSent);
                RpcContext.getContext().setFuture(null);
                return new RpcResult();
            } else if (isAsync) {
            	ResponseFuture future = currentClient.request(inv, timeout) ;
                RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));
                return new RpcResult();
            } else {
            	RpcContext.getContext().setFuture(null);
                return (Result) currentClient.request(inv, timeout).get();
            }
        } catch (TimeoutException e) {
            throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        } catch (RemotingException e) {
            throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }
以下是服务调用时候的流程图,和上下文获取bean对象的流程需要区分开


发布了20 篇原创文章 · 获赞 23 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/hdu09075340/article/details/71078633
今日推荐