赞
踩
面向对象有三大特征:继承、封装、多态,我们先来说说多态。
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
先来看传统的方法调用,在Java 中 All in object. 第一步是 new 一个对象,然后调用这个对象的成员方法。
实例1:
HelloService service = new HelloService();
service.sayHello();
Java 中,接口是最能体现多态的了,再来看一下多态的例子,我们把 HelloService 定义为接口,有两个实现类,我们在编码过程中向上转型用 HelloService 接口声明变量,而这两个具体实现类必定拥有 sayHello() 这一行为,因此可以直接用 HelloService 接口的实例进行方法调用,而不必关心他的具体实现:
实例2:
public interface HelloService{ void sayHello(); } public class BobHelloServiceImpl implements HelloService { @Override public void sayHello(){ System.out.println("Hello Bob!"); } } public class JackHelloServiceImpl implements HelloService { @Override public void sayHello(){ System.out.println("Hello Jack!"); } } @Test public void test(){ HelloService service = null; service = new BobHelloServiceImpl(); service.sayHello();//Hello Bob! service = new JackHelloServiceImpl(); service.sayHello();//Hello Jack! }
接口的实现类拥有该接口的所有行为(方法),利用接口可将声明与实现充分解耦,至于 Spring 就更进一步了,直接在 ApplicationContext.xml 中定义 Bean 指定 HelloService 的实现,做到了对代码的零侵入。这也是面向对象6个原则之一:面向接口编程而不是面向实现编程。
有了面向接口编程的基本思路接下来对理解远程调用就简单多了,远程方法调用分这么几个角色:
来改造一下 1. 中的例子,我们分三个子项目,分别是 rpc-provider、rpc-consumer、rpc-api 。rpc-provider 和 rpc-consumer 都依赖于 rpc-api 。三者的依赖关系如下图:
实例3:
rpc-api 的代码:
public interface HelloService{
String sayHello(String name);
}
rpc-provider,服务提供者:
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name){
return "Hello " + name;
}
}
public static void main(String[] args){
String url = "http://localhost:8080/rpc/";
RpcServer server = new RpcServer(url,HelloService.class,HelloServiceImpl.class);
server.start();
}
在实例2中 @Test 所在的方法就是 consumer ,远程方法调用跟本地方法调用的区别就是 consumer 获取 HelloService 接口的具体实现的方式变了,假设我们的远程调用框架封装为一个 InvokeProxy 类,使用代理模式来实现 RPC,这里只提供伪代码说明原理,我隐藏了具体实现,实际上很多第三方框架已经为我们做好了这一点。
rpc-consumer,服务消费端:
@Test
public void test(){
InvokeProxy invokeProxy = new InvokeProxy("http://localhost:8080/rpc/");
String result = (String)InvokeProxy.invoke(HelloService.class,"sayHello",new Object[]{"xiaoming"});
System.out.println(result);//Hello xiaoming
}
InvokeProxy 类的 invoke 方法接收三个参数,一为接口所在的 class ,二为要调用的方法名字符串,三为方法所需接收的参数。
来探索一下整个流程发生了什么:
http://localhost:8080/rpc/
这个跟路径上,如 sayHello 方法的访问路径就为 http://localhost:8080/rpc/sayHello
。这个过程是一个简单的基于 HTTP 的 RPC 调用服务,事实上,这也是时下流行的 RPC 框架 Hessian 的原理,Hessian 是一个基于 HTTP 的高性能 RPC 框架。当然,你也可以实现一个基于 TCP 的 RPC 框架,原理都是类似的。
如果你关注微服务或者远程调用,那么对 Dubbo、RMI、REST 这几个名词应该不会陌生,接下来的文章我们将继续探索。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。