不灭的焱

革命尚未成功,同志仍须努力下载JDK17

作者:Albert.Wen  添加时间:2018-11-04 20:08:25  修改时间:2024-04-24 17:16:17  分类:Java基础  编辑

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

 

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

 

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进行封装

 

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容器完成这些代理的完成,这样做的好处不言而喻

 

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

 

 

摘自:https://blog.csdn.net/linuu/article/details/52794932