原文链接:http://www.zhaochao.net/index.php/2016/03/11/20/
在企业开发中,最基本的开发架构可能就算是MVC框架,如 Struts+Spring+Hibernate 或者 SpringMVC+Spring+Mybatis ,这些框架也可能是JAVA学习者第一次接触到的,运用这些框架基本上可以满足小型项目的开发,但是当项目变的复杂,业务增长迅猛时,所有代码打在一个war包,所有开发人员在同一个项目中开发,开发成本会大大提升,维护,发布,编译,测试将会是一件很头疼的事。这时就需运用RPC(Remote Procedure Call Protocol)——远程过程调用协议,框架来重构项目,将基础服务层拆分开,部署成服务形式,运用生产者消费者模型,达到解耦作用。在RPC框架实现原理中,JAVA主要采用的动态代理技术,所以简要介绍一下此技术,当作备忘录。
动态代理的目的就是在不污染类的情况下,将调用类的方法代理到别的类方法中。这是我自己总结的,感觉有点不好懂,我们来看一个实例
public interface People {
public String sayHello(String name);
}
这个接口很简单,只有一个sayHello的方法,有一个String类型的参数
public class Man implements People {
public String sayHello(String name) {
System.out.println("call Man sayHello ");
return "Hello "+name;
}
}
这个Man类也非常简单,它实现的People接口中的sayHello方法,返回 “Hello”+参数名,并且打印出 “call Man sayHello ” 表明这个方法被调用了。
public class PeopleProxyHandler implements InvocationHandler {
private Object object;
public PeopleProxyHandler(Object object){
this.object=object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" call peopleProxyHandler invoke ");
System.out.println("调用对象为:"+object.getClass().getName());
System.out.println("调用方法为:"+method.getName());
for (Object obj:args){
System.out.println("参数为:"+obj.toString());
}
Class cl=Class.forName(object.getClass().getName());
return method.invoke(cl.newInstance(),args);
}
}
这个类是关键,它实现了InvocationHandler 接口,有一个构造函数,并且有一个invoke方法,这个类的主要作用就是在将调用类方法时将调用的方法名和参数代理到invoke方法中。在invoke 方法中,我们获取到了方法method和调用参数列表args,并打印出了一些信息方便调试。如果在构造类时我们把调用对象传过来,我们就可以通过反射来调用代理到的对象了。
public static void main(String [] rags){
People man=new Man();
People people=(People) Proxy.newProxyInstance(Man.class.getClassLoader(),new Class [] {People.class},new PeopleProxyHandler(man));
String res=people.sayHello("zhaochao");
System.out.println(res);
System.out.println(man.sayHello("zhaochao"));
}
在这个测试方法中,我们先创建了一个对象,然后利用Proxy.newProxyInstance()获得了一个man的代理对象people,最后调用了这个代理对象的sayHello方法。
call peopleProxyHandler invoke
调用对象为:com.zhaocaho.proxy.Man
调用方法为:sayHello
参数为:zhaochao
call Man sayHello
Hello zhaochao
call Man sayHello
Hello zhaochao
在结果中我们可以看到当调用people.sayHello时并没有直接调用Man中的sayHello方法,而是调用了PeopleProxyHandler 中的invoke 方法,并且将方法和参数传进去了,在invoke中我们通过反射调用了man中的sayHello方法,最后返回结果和直接调用man中的sayHello是完全一样的。
总结
通过上面例子我们可以发现,如果在invoke方法中,我们将方法名,参数,对象名通过网络传送到远程服务器上,在远程服务器上接收到数据,然后通过反射调用该对象的方法,最后通过网络返回结果,invoke通过网络收到结果后将结果析封装后返回,这样对于people这个对象来说它并不知道,底层到底是通过什么方式完成此次方法调用的,只要返回结果和它调用本地方法一样就达到本次调用目的了。这就是RPC的基本原理,当然实现起来没有这么简单,细节知识,未完待续!