1.1. 什么是RPC
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。
和传统的WebService相比,WebService是一种SOAP的服务,是基于HTTP的一种服务。
rpc是远程过程调用,你可以这么理解,就是在另外一台服务器上有一段代码(函数),你可以通过网络远程调用它。用什么协议(http,tcp,udp…),传输什么数据格式(json,xml,二进制…)你都可以自己定义。
http只是一种应用层的协议,和你要写的代码没有关系。你只需要好好的了解它,并且利用好它的特性就好了。
webservice,顾名思义这也是一种提供service的形式,只是它是通过http(web)来提供service而已。你可以基于http来提供你想提供的任意的服务,可以是rpc,也可以是restful。
1.web service是运行在web上的一个服务。他实现了 不同系统不同平台,不同开发语言和开发技术实现的软件系统之间的通讯。它的数据传输形式显得更加的丰富,除了以SOAP为代表的xml传输形式,还可以是JSON、protocol buffer等传输形式。web service可以通过web的方式进行查看。web service可以是B/S或者是C/S的架构。
2.web service现在移动互联网的手机和平台以及平台和平台之间的通信使用极为广泛,RPC在一些后台的接口操作(推送、同步、命令操作)和系统间通信仍然在广泛的使用。
3.都可以作为远程调用的方式 载体协议不同而已。
4.webservice框架在开发中太重。
2.在业务需求中组要使用到了RPC框架,去调用远程服务,下面就介绍一下本文提到的自定义RPC框架设计思路
在我自己看来就是可以调用不在本地的服务,便于分布式开发,相对于阿里,京东数据量非常大的业务,会把各个模块部署在不同的服务器上,便于高度解耦和维护。最重要的一点就是可以大批量的处理业务量。
可以实现分布式远程调用,很方便的将业务发布为服务,客户端可以很方便的像调用本地一样调用远程的服务。
草图:
设计步骤:
1.服务端。
思路:远程服务提供具体的业务实现,服务器实现自定义的RPC框架,作为客户端只要按照传统的注解将接口注入,后面所有的实际注入bean 和调用实例以及方法全部通过框架来实现。
- Spring扫描注解,将具体公共业务实现类添加到hashmap中,数据结构为 {接口名,实现类对象object}
- 向zookeeper注册服务器,数据结构为{接口,服务器地址}
- 通过反射的方式调用实现类对象。
- 通过动态代理调用客户端请求的方法Method.invoke(serviceImplObj,paramargs)
代码实现:
1.MyServer.java
@Component
// ApplicationContextAware会为Component组件调用setApplicationContext方法; 测试Myserver3时注释
public class MyServer implements ApplicationContextAware
{
@SuppressWarnings("resource")
public static void main(String[] args)
{
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring2.xml");
}
public void setApplicationContext(ApplicationContext ctx)
throws BeansException
{
Map<String, Object> serviceBeanMap = ctx.getBeansWithAnnotation(RpcService.class);
for (Object serviceBean : serviceBeanMap.values())
{
try
{
// 获取自定义注解上的value
String value = serviceBean.getClass().getAnnotation(RpcService.class).value();
System.out.println("注解上的value: " + value);
// 反射被注解类,并调用指定方法
Method method = serviceBean.getClass().getMethod("hello", new Class[] {String.class});
Object invoke = method.invoke(serviceBean, "bbb");
System.out.println(invoke);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
2、RpcService.java
@Target({ElementType.TYPE})
// 注解用在接口上
@Retention(RetentionPolicy.RUNTIME)
// VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
@Component
public @interface RpcService
{
String value();
}
3.HelloService.java
public interface HelloService
{
String hello(String name);
}
4.HelloServiceImpl.java
@RpcService("HelloServicebb")
public class HelloServiceImpl implements HelloService
{
public String hello(String name)
{
return "Hello! " + name;
}
public void test()
{
System.out.println("test");
}
}
2.客户端
- 客户端主要是通过代理模式将客户机请求的接口名、方法名和参数名,
OrderService proxy=Proxy.createProxy(classLoader,interface,...)
proxy.createOrder();
invoke(proxy.method,params)
- 将这些数据封装成Request对象,通过查询zookeeper所在接口飞服务器名称。
- zookeeper通过之前绑定的端口和地址向Socket发送请求的结果,客户机将返回结果编码向服务机(socketServer)发送请求去调用业务实现类。
代理类参照:
public class ProxyBoss
{
/**
* 对接口方法进行代理
*/
@SuppressWarnings("unchecked")
public static <T> T getProxy(final int discountCoupon, final Class<?> interfaceClass, final Class<?> implementsClass)
throws Exception
{
return (T)Proxy.newProxyInstance(interfaceClass.getClassLoader(),
new Class[] {interfaceClass},
new InvocationHandler()
{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
Integer returnValue = (Integer)method.invoke(implementsClass.newInstance(), args);// 调用原始对象以后返回的值
return returnValue - discountCoupon;
}
});
}
}
主要用到的技术:
- zookeeper
- java反射和动态代理
- Spring注解和自启动
- 序列化和反序列化
- netty(NIO框架)