深度解析xxl-rpc之服务调用者

一.服务的调用者

服务调用者总揽:
深度解析xxl-rpc之服务调用者_第1张图片
在remoting包中的invoker包就是服务调用者,包括配置,bean代理,负载均衡策略,调用方案等。

二.生成代理

2.1 @XxlRpcReference

我们先来看下 @XxlRpcReference注解,这个注解中定义了服务调用者的一些使用的一些策略。

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface XxlRpcReference {
    //通讯方式 ,缺省netty
    NetEnum netType() default NetEnum.NETTY;
    //序列化方式 ,缺省hessian
    Serializer.SerializeEnum serializer() default Serializer.SerializeEnum.HESSIAN;
    // 调用方式 ,缺省sync
    CallType callType() default CallType.SYNC;
    // 负载均衡策略,缺省round
    LoadBalance loadBalance() default LoadBalance.ROUND;

    // version
    String version() default "";
    // 超时时间
    long timeout() default 1000;
    // 服务提供方地址, 这边可以自己来配置
    String address() default "";
    // token 做验证使用
    String accessToken() default "";

    //XxlRpcInvokeCallback invokeCallback() ;

}
2.2 XxlRpcSpringInvokerFactory 类

如果你使用spring的话,就可以使用注解+XxlRpcSpringInvokerFactory 的方式来使用rpc。
首先看下该类的继承关系:

public class XxlRpcSpringInvokerFactory extends InstantiationAwareBeanPostProcessorAdapter implements InitializingBean,DisposableBean, BeanFactoryAware 

继承InstantiationAwareBeanPostProcessorAdapter , 实现InitializingBean,DisposableBean,BeanFactoryAware 接口。
分别说说它们的调用时机(按照顺序):

BeanFactoryAware : 注入 beanfactory 使用。可以使用beanfactory获得 spring中bean。他这边就一个setBeanFactory 方法。
InitializingBean : 在bean实例化设置完属性后调用 afterPropertiesSet方法
InstantiationAwareBeanPostProcessorAdapter: 对实例化之后的bean进行增强。调用postProcessAfterInstantiation 方法。
DisposableBean:bean 销毁的时候调用destroy方法。

有了它们的执行顺序就一下明了了。
setBeanFactory() ----> afterPropertiesSet() ---->postProcessAfterInstantiation() ---->destroy()。
可以说前三个方法是与服务调用者初始化相关的。我们挨着看下

2.2.1 setBeanFactory

这个很简单,就是将beanfactory 的引用给成员变量。

private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
2.2.2 afterPropertiesSet
 @Override
    public void afterPropertiesSet() throws Exception {
        // start invoker factory
        xxlRpcInvokerFactory = new XxlRpcInvokerFactory(serviceRegistryClass, serviceRegistryParam);
        xxlRpcInvokerFactory.start();
    }

创建XxlRpcInvokerFactory 对象,调用start方法。接下来我们看看这个类
2.2.2.1 XxlRpcProviderFactory
XxlRpcProviderFactory类主要是做了服务注册,客户端线程池响应初始化和回调线程池的初始化,客户端的 start,stop的工作。
我们来看下start 方法:
根据配置创建对应注册中心对象,调用注册中心的start方法。这里不详细解析。注册中心start 方法主要是干了 创建注册中心client并创建守护线程来刷新获取服务提供者列表。

 public void start() throws Exception {
        // start registry
        if (serviceRegistryClass != null) {
        	// 创建 注册中心 对象
            serviceRegistry = serviceRegistryClass.newInstance();
            // 调用注册中心对象的 start 方法  
            serviceRegistry.start(serviceRegistryParam);
        }
    }

接下来看下stop方法:

 public void  stop() throws Exception {
        // stop registry  停止注册中心客户端
        if (serviceRegistry != null) {
            serviceRegistry.stop();
        }

        // stop callback  执行停止回调方法
        if (stopCallbackList.size() > 0) {
            for (BaseCallback callback: stopCallbackList) {
                try {
                    callback.run();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }

        // stop CallbackThreadPool  关闭线程池
        stopCallbackThreadPool();
    }
2.2.3 postProcessAfterInstantiation

先看一下这段代码,在关键的位置加了注释,很简单也很好理解。

 @Override
    public boolean postProcessAfterInstantiation(final Object bean, final String beanName) throws BeansException {

        // collection
        final Set serviceKeyList = new HashSet<>();

        // parse XxlRpcReferenceBean
        ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() {
            @Override
            public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                // 字段 是否有XxlRpcReference 注解
                if (field.isAnnotationPresent(XxlRpcReference.class)) {
                    // valid 获取字段的类型
                    Class iface = field.getType();
                    // 字段不是 接口抛出异常
                    if (!iface.isInterface()) {
                        throw new XxlRpcException("xxl-rpc, reference(XxlRpcReference) must be interface.");
                    }
                    // 获取注解信息,
                    XxlRpcReference rpcReference = field.getAnnotation(XxlRpcReference.class);

                    // init reference bean   创建 referenceBean , 设置一些需要的参数 ,将注解中的参数 设置到referenceBean 对象中。
                    XxlRpcReferenceBean referenceBean = new XxlRpcReferenceBean(
                            rpcReference.netType(),
                            rpcReference.serializer().getSerializer(),
                            rpcReference.callType(),
                            rpcReference.loadBalance(),
                            iface,
                            rpcReference.version(),
                            rpcReference.timeout(),
                            rpcReference.address(),
                            rpcReference.accessToken(),
                            null,
                            xxlRpcInvokerFactory
                    );
                    // 调用 getObject方法, 这个方法主要使用生成代理对象的。
                    Object serviceProxy = referenceBean.getObject();

                    // set bean
                    field.setAccessible(true);
                    //给这个字段赋值 
                    field.set(bean, serviceProxy);

                    logger.info(">>>>>>>>>>> xxl-rpc, invoker factory init reference bean success. serviceKey = {}, bean.field = {}.{}",
                            XxlRpcProviderFactory.makeServiceKey(iface.getName(), rpcReference.version()), beanName, field.getName());

                    // collection    根据这个接口全类名与 version生成 servicekey  ,跟服务提供者一眼的
                    String serviceKey = XxlRpcProviderFactory.makeServiceKey(iface.getName(), rpcReference.version());
                    serviceKeyList.add(serviceKey);

                }
            }
        });
  
        // mult discovery  进行服务发现, 本地缓存一下 这个key的服务提供者
        if (xxlRpcInvokerFactory.getServiceRegistry() != null) {
            try {
                xxlRpcInvokerFactory.getServiceRegistry().discovery(serviceKeyList);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }

        return super.postProcessAfterInstantiation(bean, beanName);
    }

该方法 主要是找出带有XxlRpcReference注解的成员变量。然后解析XxlRpcReference注解中的参数,创建XxlRpcReferenceBean对象,生成代理对象,然后将代理对象赋值给这个字段,这样,在我们使用这个service的时候,真正调用的就是这个代理对象。接下来我们要看下这个XxlRpcReferenceBean 类了。
2.2.3.1 XxlRpcReferenceBean
可以根据这个类生成代理对象,也就是我们常说的客户端stub。
首先,我们先来看下该类的字段与构造

private NetEnum netType;
	private Serializer serializer;  // 序列化方式,hession
	private CallType callType;  // 调用方式
	private LoadBalance loadBalance;  //负载均衡策略

	private Class iface;  // 接口class对象
	private String version;  // 版本

	private long timeout = 1000; //超时时间

	private String address;  // 服务提供者地址
	private String accessToken;// token

	private XxlRpcInvokeCallback invokeCallback;

	private XxlRpcInvokerFactory invokerFactory;  // invoker factory

	public XxlRpcReferenceBean(NetEnum netType,
							   Serializer serializer,
							   CallType callType,
							   LoadBalance loadBalance,
							   Class iface,
							   String version,
							   long timeout,
							   String address,
							   String accessToken,
							   XxlRpcInvokeCallback invokeCallback,
							   XxlRpcInvokerFactory invokerFactory
	) {

		this.netType = netType;
		this.serializer = serializer;
		this.callType = callType;
		this.loadBalance = loadBalance;
		this.iface = iface;
		this.version = version;
		this.timeout = timeout;
		this.address = address;
		this.accessToken = accessToken;
		this.invokeCallback = invokeCallback;
		this.invokerFactory = invokerFactory;

		// valid
		if (this.netType==null) {
			throw new XxlRpcException("xxl-rpc reference netType missing.");
		}
		if (this.serializer==null) {
			throw new XxlRpcException("xxl-rpc reference serializer missing.");
		}
		if (this.callType==null) {
			throw new XxlRpcException("xxl-rpc reference callType missing.");
		}
		if (this.loadBalance==null) {
			throw new XxlRpcException("xxl-rpc reference loadBalance missing.");
		}
		if (this.iface==null) {
			throw new XxlRpcException("xxl-rpc reference iface missing.");
		}
		if (this.timeout < 0) {
			this.timeout = 0;
		}
		if (this.invokerFactory == null) {
			this.invokerFactory = XxlRpcInvokerFactory.getInstance();
		}

		// init Client
		initClient();
	}

在构造最后调用了一个 initClient方法。 这个方法主要是创建client对象,初始化参数。
然后我们再来看下,服务调用者 核心 :代理对象的生成
getObject 方法就是生成某个服务的代理对象。使用技术就是jdk的proxy。


	public Object getObject() {
		return Proxy.newProxyInstance(Thread.currentThread()
				.getContextClassLoader(), new Class[] { iface },
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

						// method param 生成一些 调用参数
						String className = method.getDeclaringClass().getName();	// iface.getName()
						String varsion_ = version;
						// 方法名
						String methodName = method.getName();
						//方法参数类型
						Class[] parameterTypes = method.getParameterTypes();
						// 方法参数值
						Object[] parameters = args;

						// filter for generic
						// 这个就是判断是否是泛化调用,如果是泛化调用,参数就按照用户配置的来,比如说 你要调用哪个类,方法名,参数类型,参数值。这些都要
						// 设定好
						if (className.equals(XxlRpcGenericService.class.getName()) && methodName.equals("invoke")) {

							Class[] paramTypes = null;
							if (args[3]!=null) {
								String[] paramTypes_str = (String[]) args[3];
								if (paramTypes_str.length > 0) {
									paramTypes = new Class[paramTypes_str.length];
									for (int i = 0; i < paramTypes_str.length; i++) {
										paramTypes[i] = ClassUtil.resolveClass(paramTypes_str[i]);
									}
								}
							}

							className = (String) args[0];
							varsion_ = (String) args[1];
							methodName = (String) args[2];
							parameterTypes = paramTypes;
							parameters = (Object[]) args[4];
						}	
						// 这边就是确认一下 你这方法是出自哪个类的
						// filter method like "Object.toString()"
						if (className.equals(Object.class.getName())) {
							logger.info(">>>>>>>>>>> xxl-rpc proxy class-method not support [{}#{}]", className, methodName);
							throw new XxlRpcException("xxl-rpc proxy class-method not support");
						}
						
						// 服务提供者 地址的选择, 根据负载均衡策略来选择
						String finalAddress = address;
						if (finalAddress==null || finalAddress.trim().length()==0) {
							if (invokerFactory!=null && invokerFactory.getServiceRegistry()!=null) {
								// discovery
								String serviceKey = XxlRpcProviderFactory.makeServiceKey(className, varsion_);
								TreeSet addressSet = invokerFactory.getServiceRegistry().discovery(serviceKey);
								// load balance
								if (addressSet==null || addressSet.size()==0) {
									// pass
								} else if (addressSet.size()==1) {  // 就一个的时候,那就选第一个
									finalAddress = addressSet.first();
								} else { // 负载均衡
									finalAddress = loadBalance.xxlRpcInvokerRouter.route(serviceKey, addressSet);
								}

							}
						}
						
						// 最后调用地址还是 null 就抛出异常了
						if (finalAddress==null || finalAddress.trim().length()==0) {
							throw new XxlRpcException("xxl-rpc reference bean["+ className +"] address empty");
						}

						// request 请求参数封住
						XxlRpcRequest xxlRpcRequest = new XxlRpcRequest();
	                    xxlRpcRequest.setRequestId(UUID.randomUUID().toString());
	                    xxlRpcRequest.setCreateMillisTime(System.currentTimeMillis());
	                    xxlRpcRequest.setAccessToken(accessToken);
	                    xxlRpcRequest.setClassName(className);
	                    xxlRpcRequest.setMethodName(methodName);
	                    xxlRpcRequest.setParameterTypes(parameterTypes);
	                    xxlRpcRequest.setParameters(parameters);
	                    
	                    // send  根据调用策略 调用
						if (CallType.SYNC == callType) {
							// future-response set
							XxlRpcFutureResponse futureResponse = new XxlRpcFutureResponse(invokerFactory, xxlRpcRequest, null);
							try {
								// do invoke
								client.asyncSend(finalAddress, xxlRpcRequest);

								// future get
								XxlRpcResponse xxlRpcResponse = futureResponse.get(timeout, TimeUnit.MILLISECONDS);
								if (xxlRpcResponse.getErrorMsg() != null) {
									throw new XxlRpcException(xxlRpcResponse.getErrorMsg());
								}
								return xxlRpcResponse.getResult();
							} catch (Exception e) {
								logger.info(">>>>>>>>>>> xxl-rpc, invoke error, address:{}, XxlRpcRequest{}", finalAddress, xxlRpcRequest);

								throw (e instanceof XxlRpcException)?e:new XxlRpcException(e);
							} finally{
								// future-response remove
								futureResponse.removeInvokerFuture();
							}
						} else if (CallType.FUTURE == callType) {
							// future-response set
							XxlRpcFutureResponse futureResponse = new XxlRpcFutureResponse(invokerFactory, xxlRpcRequest, null);
                            try {
								// invoke future set
								XxlRpcInvokeFuture invokeFuture = new XxlRpcInvokeFuture(futureResponse);
								XxlRpcInvokeFuture.setFuture(invokeFuture);

                                // do invoke
                                client.asyncSend(finalAddress, xxlRpcRequest);

                                return null;
                            } catch (Exception e) {
								logger.info(">>>>>>>>>>> xxl-rpc, invoke error, address:{}, XxlRpcRequest{}", finalAddress, xxlRpcRequest);

								// future-response remove
								futureResponse.removeInvokerFuture();

								throw (e instanceof XxlRpcException)?e:new XxlRpcException(e);
                            }

						} else if (CallType.CALLBACK == callType) {

							// get callback
							XxlRpcInvokeCallback finalInvokeCallback = invokeCallback;
							XxlRpcInvokeCallback threadInvokeCallback = XxlRpcInvokeCallback.getCallback();
							if (threadInvokeCallback != null) {
								finalInvokeCallback = threadInvokeCallback;
							}
							if (finalInvokeCallback == null) {
								throw new XxlRpcException("xxl-rpc XxlRpcInvokeCallback(CallType="+ CallType.CALLBACK.name() +") cannot be null.");
							}

							// future-response set
							XxlRpcFutureResponse futureResponse = new XxlRpcFutureResponse(invokerFactory, xxlRpcRequest, finalInvokeCallback);
							try {
								client.asyncSend(finalAddress, xxlRpcRequest);
							} catch (Exception e) {
								logger.info(">>>>>>>>>>> xxl-rpc, invoke error, address:{}, XxlRpcRequest{}", finalAddress, xxlRpcRequest);

								// future-response remove
								futureResponse.removeInvokerFuture();

								throw (e instanceof XxlRpcException)?e:new XxlRpcException(e);
							}

							return null;
						} else if (CallType.ONEWAY == callType) {
                            client.asyncSend(finalAddress, xxlRpcRequest);
                            return null;
                        } else {
							throw new XxlRpcException("xxl-rpc callType["+ callType +"] invalid");
						}

					}
				});
	}

这个方法虽然看起来非常的长,但是也不是很麻烦,主要干了这些事情:
1⃣️.获取请求的一些参数,包括你要调哪个类,哪个方法,方法参数类型,方法参数值。
2⃣️. 如果是泛化调用(你自己指定1⃣️里面的字段)类,方法名,方法参数类型,方法参数 就要按照你指定的来。
3⃣️.服务提供者地址的选择,根据负载均衡策略来,你自己在注解中配置的优先级最低(这个有点想不通)。
4⃣️.封装请求参数,将类,方法名,方法参数类型,方法参数值,还有一个唯一的uuid ,封装成Request对象实体。
5⃣️.根据调用策略来进行调用。

总结

本文章主要是讲了xxl-rpc 服务调用者生成的大体流程,从配置到注册中心的连接 到 生成referencebean 再到 生成代理对象。通过这篇文章我们能够了解到rpc服务调用方其实就是在本服务生成了一个调用对象。 这里并没有深入的讲解其中的细节,比如说调用策略,客户端网络通信,负载均衡等等。这些后续章节会详细讲解。

你可能感兴趣的:(java,rpc,深度解析xxl-rpc)