一起写RPC框架(二十二)RPC服务消费者四--服务消费者服务编织

对于远程调用来说,最高境界就是让使用者不知道此处代码是远程调用一样,感觉就是调用本地的某个普通方法,封装底层调用的细节,这是我们服务消费端最后要做的事情


比如,消费者需要调用此接口的方法

package org.laopopo.example.generic.test_2;

import org.laopopo.client.annotation.RPConsumer;

public interface HelloService {

	@RPConsumer(serviceName="LAOPOPO.TEST.SAYHELLO")
	String sayHello(String str);
	
}

对于他来说,最最简单的方式就是:

String str = helloService.sayHello("Lyncc");

这样才是最好用的RPC方式,但是如果仅仅是这样,我们肯定是调不通的,所以我们需要对helloService进行封装

HelloService helloService = ProxyFactory.factory(HelloService.class).consumer(client).timeoutMillis(3000l).newProxyInstance();


ProxyFactory.java

package org.laopopo.client.consumer.proxy;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.laopopo.client.annotation.RPConsumer;
import org.laopopo.client.consumer.Consumer;
import org.laopopo.common.utils.Proxies;
import org.laopopo.common.utils.UnresolvedAddress;

/**
 * 
 * @author BazingaLyn
 * @description 代理工厂类,用于对服务接口的编织
 * @time 2016年9月1日
 * @modifytime
 */
public class ProxyFactory<T> {
	
	
	private final Class<T> interfaceClass; 					//编织对象
	private Consumer consumer; 			   			//维护一个消费客户端
	private List<UnresolvedAddress> addresses;		       <span style="white-space:pre">		</span>//该服务的直连url集合
	private long timeoutMillis;						//接口整理超时时间
        private Map<String, Long> methodsSpecialTimeoutMillis;                  //每个方法特定的超时时间
    
	public static <I> ProxyFactory<I> factory(Class<I> interfaceClass) {
        ProxyFactory<I> factory = new ProxyFactory<>(interfaceClass);
        // 初始化数据
        factory.addresses = new ArrayList<UnresolvedAddress>();

        return factory;
    }
	
	/**
	 * 设置接口对象
	 * @param interfaceClass
	 */
	private ProxyFactory(Class<T> interfaceClass) {
        this.interfaceClass = interfaceClass;
    }
	
	/**
	 * 设置该代理工厂的唯一的消费端
	 * @param consumer
	 * @return
	 */
	public ProxyFactory<T> consumer(Consumer consumer) {
        this.consumer = consumer;
        return this;
    }
	
	/**
	 * 增加直连对象的url
	 * @param addresses
	 * @return
	 */
	public ProxyFactory<T> addProviderAddress(UnresolvedAddress... addresses) {
        Collections.addAll(this.addresses, addresses);
        return this;
    }
	
	/**
	 * 
	 * @param timeoutMillis
	 * @return
	 */
    public ProxyFactory<T> timeoutMillis(long timeoutMillis) {
        this.timeoutMillis = timeoutMillis;
        return this;
    }

    public ProxyFactory<T> methodSpecialTimeoutMillis(String methodName, long timeoutMillis) {
        methodsSpecialTimeoutMillis.put(methodName, timeoutMillis);
        return this;
    }
	
	public T newProxyInstance() {
		Method[] methods = interfaceClass.getMethods();
		if(methods == null || methods.length == 0){
			 throw new UnsupportedOperationException("the interfaceClass has no any methods");
		}
		
		boolean isAnnotation = false;
		
		for(Method method : methods){
			
			RPConsumer consumerAnnotation = method.getAnnotation(RPConsumer.class);
			if(null != consumerAnnotation){
				isAnnotation = true;
			}
			String serviceName = consumerAnnotation.serviceName();
			
			if(addresses != null && addresses.size() > 0){
				for (UnresolvedAddress address : addresses) {
		            consumer.addChannelGroup(serviceName, consumer.group(address));
		            
		        }
			}
		}
		
		if(!isAnnotation){
			throw new UnsupportedOperationException("the interfaceClass no any annotation [@RPConsumer]");
		}
		
		Object handler = new SynInvoker(consumer,timeoutMillis,methodsSpecialTimeoutMillis);
		
		return Proxies.getDefault().newProxy(interfaceClass, handler);
	}

}

基本的思路就是这样的,对调用的方法进行代理,让使用者觉得就像调用本地的方法


当然这些操作其实最优的方式就是在spring中完成,当项目使用spring管理的时候,我们可以在spring容器完成这些代理的完成,这样做的好处不言而喻


这边的代码可以直接查看源码~



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值