motan源码分析四:客户端调用服务

x33g5p2x  于2021-12-21 转载在 其他  
字(7.3k)|赞(0)|评价(0)|浏览(265)

在第一章中,我们分析了服务的发布与注册,本章中将简单的分析一下客户端调用服务的代码及流程,本文将以spring加载的方式进行分析。

1.在DemoRpcClient类的main()方法中加载类:

ApplicationContext ctx =  new  ClassPathXmlApplicationContext( new  String[]{ "classpath:motan_demo_client.xml" });
 
MotanDemoService service = (MotanDemoService) ctx.getBean( "motanDemoReferer" );

2.上面加载了spring的配置文件motan_demo_client.xml

<motan:registry regProtocol="zookeeper" name="registry" address="127.0.0.1:2181" connectTimeout="2000"/>

    <!-- motan协议配置 -->
    <motan:protocol default="true" name="motan" haStrategy="failover"loadbalance="roundrobin" maxClientConnection="10" minClientConnection="2"/>

    <!-- 通用referer基础配置 -->
    <motan:basicReferer requestTimeout="200" accessLog="false"retries="2" group="motan-demo-rpc" module="motan-demo-rpc"application="myMotanDemo" protocol="motan" registry="registry"id="motantestClientBasicConfig" throwException="false" check="true"/>

    <!-- 具体referer配置。使用方通过beanid使用服务接口类 -->
    <motan:referer id="motanDemoReferer"
                   interface="com.weibo.motan.demo.service.MotanDemoService"connectTimeout="300" requestTimeout="300" basicReferer="motantestClientBasicConfig"/>

经过spring装载RefererConfig后,每次向spring框架getBean时会调用RefererConfig的getRef()方法

3.获取接口MotanDemoService的实现类代码如下:

publicObject getRef()
    {
        if(ref == null)
            initRef();//初始化
        returnref;
    }

    public synchronized voidinitRef()
    {
        if(initialized.get())
            return;
        try{
            interfaceClass = Class.forName(interfaceClass.getName(), true, Thread.currentThread().getContextClassLoader());
        }
        catch(ClassNotFoundException e)
        {
            throw new MotanFrameworkException((new StringBuilder("ReferereConfig initRef Error: Class not found ")).append(interfaceClass.getName()).toString(), e, MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
        }
        if(CollectionUtil.isEmpty(protocols))//protocol配置是否为空
            throw new MotanFrameworkException(String.format("%s RefererConfig is malformed, for protocol not set correctly!", newObject[] {
                interfaceClass.getName()
            }));
        checkInterfaceAndMethods(interfaceClass, methods);
        clusterSupports = newArrayList(protocols.size());//初始化集群支持类列表,可以支持多个
        List clusters = newArrayList(protocols.size());//初始化集群类列表,可以支持多个
        String proxy = null;
        ConfigHandler configHandler = (ConfigHandler)ExtensionLoader.getExtensionLoader(com/weibo/api/motan/config/handler/ConfigHandler).getExtension("default");//加载SimpleConfigHandler
        List registryUrls =loadRegistryUrls();//加载注册中心url列表,可以支持多个注册中心
        String localIp =getLocalHostAddress(registryUrls);
        for(Iterator iterator =protocols.iterator(); iterator.hasNext();)
        {
            ProtocolConfig protocol =(ProtocolConfig)iterator.next();
            LoggerUtil.info((new StringBuilder("ProtocolConfig's")).append(protocol.getName()).toString());
            Map params = newHashMap();
            params.put(URLParamType.nodeType.getName(), "referer");
            params.put(URLParamType.version.getName(), URLParamType.version.getValue());
            params.put(URLParamType.refreshTimestamp.getName(), String.valueOf(System.currentTimeMillis()));
            collectConfigParams(params, newAbstractConfig[] {
                protocol, basicReferer, extConfig, this});
            collectMethodConfigParams(params, getMethods());
            URL refUrl = new URL(protocol.getName(), localIp, 0, interfaceClass.getName(), params);
            ClusterSupport clusterSupport =createClusterSupport(refUrl, configHandler, registryUrls);
            clusterSupports.add(clusterSupport);
            clusters.add(clusterSupport.getCluster());
            proxy = proxy != null ?proxy : refUrl.getParameter(URLParamType.proxy.getName(), URLParamType.proxy.getValue());
        }

        ref =configHandler.refer(interfaceClass, clusters, proxy);//调用SimpleConfigHandler的refer方法获取接口实现类
        initialized.set(true);
    }

4.下面我们来看一下SimpleConfigHandler的refer方法的代理实现,使用了jdk的动态代理技术

  public  <T> T refer(Class<T> interfaceClass, List<Cluster<T>> clusters, String proxyType) {
         ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory. class ).getExtension(proxyType); //创建代理工厂
         return  proxyFactory.getProxy(interfaceClass,  new  RefererInvocationHandler<T>(interfaceClass, clusters)); //获取代理类
     }
 
public  class  JdkProxyFactory  implements  ProxyFactory {
 
     @SuppressWarnings ( "unchecked" )
     public  <T> T getProxy(Class<T> clz, InvocationHandler invocationHandler) {
         return  (T) Proxy.newProxyInstance( this .getClass().getClassLoader(),  new  Class[] {clz}, invocationHandler); //使用jdk的动态代理,实际调用的代码是下面的的invoke方法
     }
 
}
 
 
     public  Object invoke(Object proxy, Method method, Object[] args)  throws  Throwable {
         DefaultRequest request =  new  DefaultRequest(); //封装通信用的request,request和response是在客户端和服务端通信的两个对象
 
         request.setRequestId(RequestIdGenerator.getRequestId());
         request.setArguments(args);
         request.setMethodName(method.getName());
         request.setParamtersDesc(ReflectUtil.getMethodParamDesc(method));
         request.setInterfaceName(clz.getName());
         request.setAttachment(URLParamType.requestIdFromClient.getName(), String.valueOf(RequestIdGenerator.getRequestIdFromClient()));
 
         // 当 referer配置多个protocol的时候,比如A,B,C,
         // 那么正常情况下只会使用A,如果A被开关降级,那么就会使用B,B也被降级,那么会使用C
         for  (Cluster<T> cluster : clusters) { //motan支持多个protocol的配置,也就是支持多个cluster,但是默认情况下只取第一个,如果前面的被降级,则取下一个
             String protocolSwitcher = MotanConstants.PROTOCOL_SWITCHER_PREFIX + cluster.getUrl().getProtocol();
 
             Switcher switcher = switcherService.getSwitcher(protocolSwitcher);
 
             if  (switcher !=  null  && !switcher.isOn()) {
                 continue ;
             }
             List<Referer<T>> referL = cluster.getReferers(); //此段代码为我单独添加的,目的是证明客户端在配置多个注册中心的情况下,cluster可以支持跨注册中心的调用
             for (Referer<T> refer : referL){
                 LoggerUtil.info(refer.getServiceUrl().getUri()+refer.getServiceUrl().getPath());
             }
             request.setAttachment(URLParamType.version.getName(), cluster.getUrl().getVersion());
             request.setAttachment(URLParamType.clientGroup.getName(), cluster.getUrl().getGroup());
             // 带上client的application和module
             request.setAttachment(URLParamType.application.getName(), ApplicationInfo.getApplication(cluster.getUrl()).getApplication());
             request.setAttachment(URLParamType.module.getName(), ApplicationInfo.getApplication(cluster.getUrl()).getModule());
             Response response =  null ;
             boolean  throwException =
                     Boolean.parseBoolean(cluster.getUrl().getParameter(URLParamType.throwException.getName(),
                             URLParamType.throwException.getValue()));
             try  {
                 response = cluster.call(request); //调用cluster的call方法
                 return  response.getValue(); //获取返回信息
             }  catch  (RuntimeException e) {
                 if  (ExceptionUtil.isBizException(e)) {
                     Throwable t = e.getCause();
                     // 只抛出Exception,防止抛出远程的Error
                     if  (t !=  null  && t  instanceof  Exception) {
                         throw  t;
                     }  else  {
                         String msg =
                                 t ==  null  ?  "biz exception cause is null"  : ( "biz exception cause is throwable error:"  + t.getClass()
                                         +  ", errmsg:"  + t.getMessage());
                         throw  new  MotanServiceException(msg, MotanErrorMsgConstant.SERVICE_DEFAULT_ERROR);
                     }
                 }  else  if  (!throwException) {
                     LoggerUtil.warn( "RefererInvocationHandler invoke false, so return default value: uri="  + cluster.getUrl().getUri()
                             +  " "  + MotanFrameworkUtil.toString(request), e);
                     return  getDefaultReturnValue(method.getReturnType());
                 }  else  {
                     LoggerUtil.error(
                             "RefererInvocationHandler invoke Error: uri="  + cluster.getUrl().getUri() +  " "
                                     + MotanFrameworkUtil.toString(request), e);
                     throw  e;
                 }
             }
         }
 
         throw  new  MotanServiceException( "Referer call Error: cluster not exist, interface="  + clz.getName() +  " "
                 + MotanFrameworkUtil.toString(request), MotanErrorMsgConstant.SERVICE_UNFOUND);
 
     }

本章知识点总结:

1.客户端在获取业务接口的实现类时,使用了jdk的动态代理技术;

2.客户端可以支持多个注册中心;

3.客户端可以支持多个cluster,但是只取最前面有效那个;

4.使用request和response对象进行信息的传递。

相关文章