dubbox rest调用过程分析

前提是熟悉dubbo的调用过程,这里直接从AbstractProxyProtocol开始分析:

 

    public <T> Invoker<T> refer(final Class<T> type, final URL url) throws RpcException {
        final Invoker<T> tagert = proxyFactory.getInvoker(doRefer(type, url), type, url);
        Invoker<T> invoker = new AbstractInvoker<T>(type, url) {
            @Override
            protected Result doInvoke(Invocation invocation) throws Throwable {
                try {
                    Result result = tagert.invoke(invocation);
                    Throwable e = result.getException();
                    if (e != null) {
                        for (Class<?> rpcException : rpcExceptions) {
                            if (rpcException.isAssignableFrom(e.getClass())) {
                                throw getRpcException(type, url, invocation, e);
                            }
                        }
                    }
                    return result;
                } catch (RpcException e) {
                    if (e.getCode() == RpcException.UNKNOWN_EXCEPTION) {
                        e.setCode(getErrorCode(e.getCause()));
                    }
                    throw e;
                } catch (Throwable e) {
                    throw getRpcException(type, url, invocation, e);
                }
            }
        };
        invokers.add(invoker);
        return invoker;
    }

其中的doRefer(type,url)会调用RestProtocol的doRefer

 

 

 protected <T> T doRefer(Class<T> serviceType, URL url) throws RpcException {
        if (connectionMonitor == null) {
            connectionMonitor = new ConnectionMonitor();
        }
        // TODO more configs to add
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();//cuihs,deprecated替换
//        PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
        // 20 is the default maxTotal of current PoolingClientConnectionManager
        connectionManager.setMaxTotal(url.getParameter(Constants.CONNECTIONS_KEY, 20));//连接数默认是20
        connectionManager.setDefaultMaxPerRoute(url.getParameter(Constants.CONNECTIONS_KEY, 20));
        connectionMonitor.addConnectionManager(connectionManager);
        SocketConfig socketConfig = SocketConfig.custom()
        		.setTcpNoDelay(true)
        		.setSoKeepAlive(true)
        		.build();//cuihs
        connectionManager.setDefaultSocketConfig(socketConfig);//cuihs
//      BasicHttpContext localContext = new BasicHttpContext();

//        DefaultHttpClient httpClient = new DefaultHttpClient(connectionManager);
        ConnectionKeepAliveStrategy kaStrategy = new ConnectionKeepAliveStrategy() {//cuihs
          public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
          HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
          while (it.hasNext()) {
              HeaderElement he = it.nextElement();
              String param = he.getName();
              String value = he.getValue();
              if (value != null && param.equalsIgnoreCase("timeout")) {
                  return Long.parseLong(value) * 1000;
              }
          }
          // TODO constant
          return 30 * 1000;//如果没有设置保活时间,默认30s
      }
  };
        RequestConfig defaultRequestConfig = RequestConfig.custom()
        		.setConnectTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT))
        		.setSocketTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT))
        		.build();

        CloseableHttpClient httpClient = HttpClients.custom()
        		                      .setKeepAliveStrategy(kaStrategy)
        		                      .setConnectionManager(connectionManager)
        		                      .setDefaultRequestConfig(defaultRequestConfig)
        		                      .build();//cuihs
//        httpClient.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {
//            public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
//                HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
//                while (it.hasNext()) {
//                    HeaderElement he = it.nextElement();
//                    String param = he.getName();
//                    String value = he.getValue();
//                    if (value != null && param.equalsIgnoreCase("timeout")) {
//                        return Long.parseLong(value) * 1000;
//                    }
//                }
//                // TODO constant
//                return 30 * 1000;//如果没有设置保活时间,默认30s
//            }
//        });
        
//        HttpParams params = httpClient.getParams();
        // TODO currently no xml config for Constants.CONNECT_TIMEOUT_KEY so we directly reuse Constants.TIMEOUT_KEY for now
        /** 连接建立的超时*/
//        HttpConnectionParams.setConnectionTimeout(params, url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
       /** Socket超时*/
//        HttpConnectionParams.setSoTimeout(params, url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));
       /** 是否为了减少带宽消耗而减少数据包的发送*/
//        HttpConnectionParams.setTcpNoDelay(params, true);
        /** 是否开启TCP保活*/
//        HttpConnectionParams.setSoKeepalive(params, true);

        									
        
        ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient/*, localContext*/);

        ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
        clients.add(client);

        for (String clazz : Constants.COMMA_SPLIT_PATTERN.split(url.getParameter(Constants.EXTENSION_KEY, ""))) {
            if (!StringUtils.isEmpty(clazz)) {
                try {//向client中注册其它的类
                    client.register(Thread.currentThread().getContextClassLoader().loadClass(clazz.trim()));
                } catch (ClassNotFoundException e) {
                    throw new RpcException("Error loading JAX-RS extension class: " + clazz.trim(), e);
                }
            }
        }

        // TODO protocol
        ResteasyWebTarget target = client.target("http://" + url.getHost() + ":" + url.getPort() + "/" + getContextPath(url));
        return target.proxy(serviceType);//serviceType是一个接口类,这会生成一个接口类的代理类,通过代理类可以调用远程的方法
    }


上面的代码已经被我修改过了,因为HttpClient和httpcore两个包我做了升级。其中的主要功做就是设置了http的一些连接参数,最后调用了ResteasyWebTarget的proxy方法。

 

Resteasy代理框架和JAX-RS服务端相反,它不是在使用JAX-RS注解来匹配访问RESTFul web服务方法的请求,而是创建一个HTTP请求访问一个可以不用JAX-RS注解的RESTful web服务。

例如:

 

public interface SimpleClient  
{  
   @GET  
   @Path("basic")  
   @Produces("text/plain")  
   String getBasic();  
  
   @PUT  
   @Path("basic")  
   @Consumes("text/plain")  
   void putBasic(String body);  
  
   @GET  
   @Path("queryParam")  
   @Produces("text/plain")  
   String getQueryParam(@QueryParam("param")String param);  
  
   @GET  
   @Path("matrixParam")  
   @Produces("text/plain")  
   String getMatrixParam(@MatrixParam("param")String param);  
  
   @GET  
   @Path("uriParam/{param}")  
   @Produces("text/plain")  
   int getUriParam(@PathParam("param")int param);  
}

 

ResteasyClient client = new ResteasyClientBuilder().build();  
           ResteasyWebTarget target = client.target("http://example.com/base/uri");  
  
           SimpleClient simple = target.proxy(SimpleClient.class);  
           client.putBasic("hello world"); 


再回到AbstractProxyProtocol的refer方法,它执行完RestProtocol的doRefer之后,会调用proxyFactory.getInvoker,默认是JavassistProxyFactory.getInvoker

 

 

public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper类不能正确处理带$的类名
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

 

 

这里我们可以看到,这里对ResteasyWebTarget生成的proxy又做了一次封装,我们再进到Wrapper.getWrapper看一下

 

public static Wrapper getWrapper(Class<?> c)
    {
        while( ClassGenerator.isDynamicClass(c) ) // can not wrapper on dynamic class.
            c = c.getSuperclass();

        if( c == Object.class )
            return OBJECT_WRAPPER;

        Wrapper ret = WRAPPER_MAP.get(c);
        if( ret == null )
        {
            ret = makeWrapper(c);
            WRAPPER_MAP.put(c,ret);
        }
        return ret;
    }

 


主要的函数是makeWrapper,首先其本类型不支持基本类型做包装,setPropertyValue和getPropertyValue及invokeMethod都是类似的。

 

 

这个函数主要就是构造这三个函数。

 

private static Wrapper makeWrapper(Class<?> c)
	{
		if( c.isPrimitive() )
			throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);

		String name = c.getName();
		ClassLoader cl = ClassHelper.getCallerClassLoader(Wrapper.class);

		StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
		StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
		StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");

		c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
		c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
		c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");

		Map<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
		Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
		List<String> mns = new ArrayList<String>(); // method names.
		List<String> dmns = new ArrayList<String>(); // declaring method names.
		
		// get all public field.
		for( Field f : c.getFields() )
		{
			String fn = f.getName();
			Class<?> ft = f.getType();
			if( Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()) )
				continue;

			c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
			c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
			pts.put(fn, ft);
		}
		
		Method[] methods = c.getMethods();
		// get all public method.
		boolean hasMethod = hasMethods(methods);
		if( hasMethod ){
		    c3.append(" try{");
		}
		for( Method m : methods )
		{
			if( m.getDeclaringClass() == Object.class ) //ignore Object's method.
				continue;

			String mn = m.getName();
			c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
            int len = m.getParameterTypes().length;
            c3.append(" && ").append(" $3.length == ").append(len);
			
			boolean override = false;
			for( Method m2 : methods ) {
				if (m != m2 && m.getName().equals(m2.getName())) {
					override = true;
					break;
				}
			}
			if (override) {
				if (len > 0) {
					for (int l = 0; l < len; l ++) {
						c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
							.append(m.getParameterTypes()[l].getName()).append("\")");
					}
				}
			}
			
			c3.append(" ) { ");
			
			if( m.getReturnType() == Void.TYPE )
				c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
			else
				c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");

			c3.append(" }");
			
			mns.add(mn);
			if( m.getDeclaringClass() == c )
				dmns.add(mn);
			ms.put(ReflectUtils.getDesc(m), m);
		}
		if( hasMethod ){
		    c3.append(" } catch(Throwable e) { " );
		    c3.append("     throw new java.lang.reflect.InvocationTargetException(e); " );
	        c3.append(" }");
        }
		
		c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
		
		// deal with get/set method.
		Matcher matcher;
		for( Map.Entry<String,Method> entry : ms.entrySet() )
		{
			String md = entry.getKey();
			Method method = (Method)entry.getValue();
			if( ( matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md) ).matches() )
			{
				String pn = propertyName(matcher.group(1));
				c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
				pts.put(pn, method.getReturnType());
			}
			else if( ( matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md) ).matches() )
			{
				String pn = propertyName(matcher.group(1));
				c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
				pts.put(pn, method.getReturnType());
			}
			else if( ( matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md) ).matches() )
			{
				Class<?> pt = method.getParameterTypes()[0];
				String pn = propertyName(matcher.group(1));
				c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt,"$3")).append("); return; }");
				pts.put(pn, pt);
			}
		}
		c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
		c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");

		// make class
		long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
		ClassGenerator cc = ClassGenerator.newInstance(cl);
		cc.setClassName( ( Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw" ) + id );
		cc.setSuperClass(Wrapper.class);

		cc.addDefaultConstructor();
		cc.addField("public static String[] pns;"); // property name array.
		cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
		cc.addField("public static String[] mns;"); // all method name array.
		cc.addField("public static String[] dmns;"); // declared method name array.
		for(int i=0,len=ms.size();i<len;i++)
			cc.addField("public static Class[] mts" + i + ";");

		cc.addMethod("public String[] getPropertyNames(){ return pns; }");
		cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
		cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
		cc.addMethod("public String[] getMethodNames(){ return mns; }");
		cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
		cc.addMethod(c1.toString());
		cc.addMethod(c2.toString());
		cc.addMethod(c3.toString());

		try
		{
			Class<?> wc = cc.toClass();
			// setup static field.
			wc.getField("pts").set(null, pts);
			wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
			wc.getField("mns").set(null, mns.toArray(new String[0]));
			wc.getField("dmns").set(null, dmns.toArray(new String[0]));
			int ix = 0;
			for( Method m : ms.values() )
				wc.getField("mts" + ix++).set(null, m.getParameterTypes());
			return (Wrapper)wc.newInstance();
		}
		catch(RuntimeException e)
		{
			throw e;
		}
		catch(Throwable e)
		{
			throw new RuntimeException(e.getMessage(), e);
		}
		finally
		{
			cc.release();
			ms.clear();
			mns.clear();
			dmns.clear();
		}
	}

 

 

我们再转回到JavassistProxyFactory的getInvoker方法,得到包装类后,返回一个匿名的AbstractProxyInvoker,实现了其中的抽象方法doInvoker。

这里回到AbstractProxyProtocol.refer方法,这里返回一个匿名的AbstractInvoker,实现了其中的抽象方法doInvoker,这里的doInvoker内部最后调用上面得到的匿名的AbstractProxyInvoker的invoke方法,它的内部又会调用包装类的invokeMethod方法,最后会调用ResteasyWebTarget生成的proxy发起调用。

 

最后欢迎大家访问我的个人网站:1024s

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值