原理:
利用JAVA NIO Socket,CGLIB代理,反射,以及Spring容器技术等完成简单实现。
注意:以下代码异常处理都是直接抛出,真实项目开发请try...cathc捕获异常,并在fiannly中关闭通道(Channel)。
第一步:定义一个接口:
package com.stock.test.jdk8.proxy;
public interface HelloInterface {
String say(String content);
}
远传调用服务端的实现:
package com.stock.test.jdk8.proxy;
import org.springframework.stereotype.Service;
@Service
public class Hello implements HelloInterface{
@Override
public String say(String content) {
String returnContent = "say:"+content;
return returnContent;
}
}
第二步:封装定义远程过程调用客户端与服务端传递的参数类(注意:此处的get和set方法省略)
package com.stock.test.jdk8.proxy;
import com.stock.common.json.JsonUtils;
import com.stock.common.list.CollectionUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class ProxyParam implements Serializable {
private static final long serialVersionUID = -1L;
private String target;//目标接口
private String returnType;//返回值类型
private List paramTypes;//目标方法参数类型
private Object[] params;//目标方法参数列表
private String methodName;//目标方法名称
/**
* 增加被调用方法的参数类型,按顺序放
* @param clazz Class
*/
public void addParamType(String clazz){
if(CollectionUtils.isEmpty(paramTypes)){
paramTypes = new ArrayList<>();
}
paramTypes.add(clazz);
}
public static void main(String[] args){
System.out.println(ProxyParam.class.getCanonicalName());
}
}
第三步:代理客户端
package com.stock.test.jdk8.proxy.dynamicProxy;
import com.stock.test.jdk8.proxy.ProxyParam;
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
*
* 远程代理调用客户端
*
*/
public class ProxyClient {
/**
* 执行代理
* @param param ProxyParam
* @return Object 接口返回对象
* @throws IOException
*/
public static Object proxy(ProxyParam param) throws IOException {
// 1、获取网络通信通道
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
socketChannel.configureBlocking(false);//2、切换成非阻塞模式
ByteBuffer buffer = ByteBuffer.allocate(10240);//3、分配指定大小的缓冲区
buffer.put(param.toString().getBytes("utf-8")); //4、发送数据给服务端(ByteBuffer 默认是写模式)
buffer.flip();//切换读模式
socketChannel.write(buffer);//发送数据
buffer.clear();//清理缓冲区数据
socketChannel.shutdownOutput();
/**接收服务端的反馈*/
Selector selector = Selector.open();
socketChannel.register(selector, SelectionKey.OP_READ);
String receiveMsg = null;
while (selector.select() > 0){
Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()){
SelectionKey sk = iterator.next();
if(sk.isReadable()){
buffer.clear();
SocketChannel sc = (SocketChannel)sk.channel();
sc.read(buffer);
buffer.flip();
receiveMsg = new String(buffer.array(),0,buffer.limit(),"utf-8");
buffer.clear();
}
iterator.remove();
}
if(StringUtils.isNotBlank(receiveMsg)){
break;
}
}
// 5 、关闭通道
socketChannel.close();
return receiveMsg;
}
}
第四步:服务端
package com.stock.test.jdk8.proxy.dynamicProxy;
import com.alibaba.fastjson.JSONObject;
import com.stock.common.json.JsonUtils;
import com.stock.common.list.CollectionUtils;
import com.stock.core.utils.ApplicationContextUtil;
import com.stock.test.BaseJunit4Test;
import com.stock.test.jdk8.proxy.ProxyParam;
import org.junit.Test;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.List;
/**
*
* 测试代理服务端
*
*/
public class ProxyServer extends BaseJunit4Test {
@Test
public void server() throws IOException {
// 1、获取通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 2、切换成非阻塞模式
serverSocketChannel.configureBlocking(false);
// 3、绑定连接
serverSocketChannel.bind(new InetSocketAddress(9898));
// 4 、获取选择器
Selector selector = Selector.open();
// 5、将通道注册到选择器上,并指定:监听接收事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// 6、轮询式的获取选择器上已经“准备就绪”的时间
while(selector.select() > 0){
// 7、获取所有注册的选择器(也就是监听的所有的已就绪的监听事件(网络连接状态))
Iterator iterator = selector.selectedKeys().iterator();
//循环处理:已就绪的事件
while (iterator.hasNext()){
SelectionKey key = iterator.next();
// 8、如果是:访问已就绪
if(key.isAcceptable()){
//9、如果是:访问事件已就绪,则获取客户端连接
SocketChannel socketChannel = serverSocketChannel.accept();
//10、切换客户端通道连接为非阻塞
socketChannel.configureBlocking(false);
//11、将该客户端通道注册到选择器上
socketChannel.register(selector,SelectionKey.OP_READ);
}else if (key.isReadable()){
// 12、获取当前选择器上“读就绪”状态的通道
SocketChannel socketChannel = (SocketChannel)key.channel();
try {
// 13、读取数据
ByteBuffer buffer = ByteBuffer.allocate(10240);
StringBuffer paramStr = new StringBuffer();
int len;
while((len = socketChannel.read(buffer)) != -1){
buffer.flip();
paramStr.append(new String(buffer.array(),0,len,"utf-8"));
buffer.clear();
}
ProxyParam proxyParam = JSONObject.toJavaObject(JSONObject.parseObject(paramStr.toString()), ProxyParam.class);
//ystem.out.println(JsonUtils.format(proxyParam));
Class target = Class.forName(proxyParam.getTarget());
Object targetInstance = ApplicationContextUtil.get().getBean(target);
Method targetMethod = target.getMethod(proxyParam.getMethodName(),transformParamTyps(proxyParam.getParamTypes()));
Object result = targetMethod.invoke(targetInstance,proxyParam.getParams());
buffer.put(result.toString().getBytes("utf-8"));
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
}catch (Exception e){
e.printStackTrace();
ByteBuffer buffer = ByteBuffer.allocate(10240);
buffer.put("已收到,发生异常".getBytes("utf-8"));
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
}finally {
socketChannel.close();
}
}
iterator.remove();
}
}
}
/**
*
* @param paramType List
* @return Class[] 目标方法参数类型数组
* @throws ClassNotFoundException
*
*/
public Class[] transformParamTyps(List paramType) throws ClassNotFoundException {
if(CollectionUtils.isEmpty(paramType)){
return null;
}
Class[] classes = new Class[paramType.size()];
for( int i=0;i
第五步:代理简单实现
package com.stock.test.jdk8.proxy.dynamicProxy;
import com.stock.common.json.JsonUtils;
import com.stock.test.jdk8.proxy.ProxyParam;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
private Class> target;
public Object getInstance(Class> target){
this.target = target;
Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类
enhancer.setSuperclass(target); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("预处理——————");
ProxyParam param = new ProxyParam();
param.setTarget(this.target.getCanonicalName());
param.setParams(objects);
param.setMethodName(method.getName());
param.setReturnType(method.getReturnType().getCanonicalName());
Class[] paramTypes = method.getParameterTypes();
if(null != paramTypes && paramTypes.length > 0){
for(Class paramType : paramTypes){
System.out.println("method.getParameterTypes()-->"+paramType.getCanonicalName());
param.addParamType(paramType.getCanonicalName());
}
}
Object result = ProxyClient.proxy(param);
System.out.println("调用后操作——————");
return result;
}
}
第六步:测试
package com.stock.test.jdk8.proxy.dynamicProxy;
import com.stock.test.jdk8.proxy.HelloInterface;
public class ProxyMain {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
HelloInterface helloInterface = (HelloInterface)proxy.getInstance(HelloInterface.class);
String result = helloInterface.say("测试RPC远程过程调用");
System.err.println(result);
}
}