记录学习RPC逐步演变
一、rpc-01
1.基础准备
public interface IUserService {
User getUserById (int id);
}
@Data
public class User implements Serializable {
private int id;
private String name;
public User(int id) {
}
public User(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
2.模拟服务端
/**
* 模拟服务端
*/
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception{
ServerSocket serverSocket = new ServerSocket(8888);
while (running){
Socket s = serverSocket.accept();
System.out.println("服务端监听提示:"+s.getLocalSocketAddress().toString());
System.out.println(s.getInetAddress().toString());
System.out.println(s.getLocalAddress().toString());
System.out.println("客户端请求地址:"+s.getRemoteSocketAddress().toString());
System.out.println("我是清晰分明的分界线");
System.out.println();
process(s);
s.close();
}
serverSocket.close();
}
private static void process(Socket s) throws Exception {
// 拿到输入流
InputStream inputStream = s.getInputStream();
OutputStream outputStream = s.getOutputStream();
// 组建数据输入流对象
DataInputStream dataInputStream = new DataInputStream(inputStream);
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
// 拿到请求数据
int id = dataInputStream.readInt();
IUserService userService = new UserServiceImpl();
User user = userService.getUserById(id);
// 输出数据
dataOutputStream.writeInt(user.getId());
dataOutputStream.writeUTF(user.getName());
// 刷新
dataOutputStream.flush();
dataOutputStream.close();
dataInputStream.close();
outputStream.close();
inputStream.close();
}
}
3.客户端调用
/**
* 模仿请求端
*/
public class Client {
public static void main(String[] args) throws Exception {
Socket s = new Socket("127.0.1.1",8888);
// 创建字节数组输出流
ByteArrayOutputStream bout = new ByteArrayOutputStream();
// 创建数据输出流包装
DataOutputStream dataOutputStream = new DataOutputStream(bout);
// 写入请求值
dataOutputStream.writeInt(1);
s.getOutputStream().write(bout.toByteArray());
s.getOutputStream().flush();
// 读取 创建数据输入流
DataInputStream dataInputStream = new DataInputStream(s.getInputStream());
int id = dataInputStream.readInt();
String name = dataInputStream.readUTF();
User user = new User(id, name);
System.out.println("请求返回数据-"+user);
dataInputStream.close();
dataOutputStream.close();
bout.close();
s.close();
}
}
4.结果
服务端监听提示:/127.0.1.1:8888
/127.0.0.1
/127.0.1.1
客户端请求地址:/127.0.0.1:55967
我是清晰分明的分界线
服务端监听提示:/127.0.1.1:8888
/127.0.0.1
/127.0.1.1
客户端请求地址:/127.0.0.1:56024
我是清晰分明的分界线
**************
请求返回数据-User{id=1, name='rpc_name'}
客户端+服务的 写死代码,比较臃肿
二、rpc-02
客户端代码隐藏io细节 ,使用Stud 帮助我们处理io
1.服务端
public class Server {
private static boolean flag = true;
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
while (flag){
Socket s = serverSocket.accept();
process(s);
s.close();
}
serverSocket.close();
}
/**
* 处理信息,返回数据
* @param s
* @throws IOException
*/
private static void process(Socket s) throws IOException {
DataInputStream dataInputStream = new DataInputStream(s.getInputStream());
int id = dataInputStream.readInt();
DataOutputStream dataOutputStream = new DataOutputStream(s.getOutputStream());
dataOutputStream.writeInt(id);
dataOutputStream.writeUTF(id+"-"+new Random().nextInt(20));
dataOutputStream.flush();
dataOutputStream.close();
dataInputStream.close();
}
}
2.客户端
public class Client {
public static void main(String[] args) throws Exception{
Stub stub = new Stub();
User userById = stub.findUserById(500000);
System.out.println(userById);
}
}
public class Stub {
public User findUserById(Integer id) throws Exception{
Socket socket = new Socket("127.0.0.1",8888);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
dataOutputStream.writeInt(id);
socket.getOutputStream().write(byteArrayOutputStream.toByteArray());
socket.getOutputStream().flush();
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
int id2 = dataInputStream.readInt();
String name = dataInputStream.readUTF();
User u = new User(id2,name);
dataInputStream.close();
dataOutputStream.close();
byteArrayOutputStream.close();
socket.close();
return u;
}
}
三、rpc-03
调用端使用了JDK动态代理模式,代理客户端调用的接口,以便使用服务的提供好的接口类
1.client
public class Client {
public static void main(String[] args) {
IUserService sub = Stub.getSub();
User userById = sub.getUserById(1111);
System.out.println(userById);
}
}
public class Stub { public static IUserService getSub(){ InvocationHandler invocationHandler = new InvocationHandler() {
// 此处o是代理生成的对象类似com.sun.proxy.$Proxy0 method 要执行的方法, objests 传递的参数 @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println(Arrays.toString(o.getClass().getInterfaces())); Socket socket = new Socket("127.0.0.1",8888); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); dataOutputStream.writeInt(11111); socket.getOutputStream().write(byteArrayOutputStream.toByteArray()); socket.getOutputStream().flush(); DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); int id = dataInputStream.readInt(); String name = dataInputStream.readUTF(); User user = new User(id,name); dataInputStream.close(); dataOutputStream.close(); byteArrayOutputStream.close(); socket.close(); return user; } }; try { // Class[] c = new Class[]{IUserService.class}; // Class<?>[] interfaces = IUserService.class.getInterfaces(); Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[]{IUserService.class}, invocationHandler); return (IUserService) o; }catch (Exception e){ e.printStackTrace(); } return null; } }
四·rpc-04
使用动态传递方法,服务端接收具体数据进行具体方法处理
1.客户端
public class Client {
public static void main(String[] args) {
IUserService sub = Stub.getStub();
User userById = sub.getUserById(22222);
System.out.println(userById);
IUserService sub2 = Stub.getStub();
User userById2 = sub2.getUserById(111);
System.out.println(userById2);
}
}
public class Stub {
public static IUserService getStub(){
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Socket socket = new Socket("127.0.0.1",8888);
System.out.println(o.getClass().getName());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
// 传递方法名
objectOutputStream.writeUTF(method.getName());
//传递方法参数类型
objectOutputStream.writeObject(method.getParameterTypes());
//传递方法参数
objectOutputStream.writeObject(objects);
objectOutputStream.flush();
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
int id = dataInputStream.readInt();
String name = dataInputStream.readUTF();
User user = new User(id,name);
dataInputStream.close();
objectOutputStream.close();
socket.close();
return user;
}
};
try {
Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[]{IUserService.class}, invocationHandler);
return (IUserService) o;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
2.服务端
public class Server {
private static boolean flag = true;
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
while (flag){
Socket s = serverSocket.accept();
process(s);
s.close();
}
serverSocket.close();
}
/**
* 处理信息,返回数据
* @param s
* @throws IOException
*/
private static void process(Socket s) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ObjectInputStream objectInputStream = new ObjectInputStream(s.getInputStream());
// 传递过来的方法名称
String methodName = objectInputStream.readUTF();
// 传递过来的参数类型
Class[] parameterType = (Class[]) objectInputStream.readObject();
// 传递的参数数据
Object[] args = (Object[]) objectInputStream.readObject();
IUserService userService = new UserServiceImpl();
// 使用参数类型+参数+方法名 执行具体方法
Method method = userService.getClass().getMethod(methodName,parameterType);
User user = (User) method.invoke(userService, args);
DataOutputStream dataOutputStream = new DataOutputStream(s.getOutputStream());
dataOutputStream.writeInt(user.getId());
dataOutputStream.writeUTF(user.getName());
dataOutputStream.flush();
dataOutputStream.close();
objectInputStream.close();
}
}
五·rpc-05
支持单个接口的多方法
1.客户端
public class Client {
public static void main(String[] args) {
IUserService sub = Stub.getStub();
User userById = sub.getUserById(22222);
System.out.println(userById);
sub.run();
}
}
public class Stub {
public static IUserService getStub(){
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Socket socket = new Socket("127.0.0.1",8888);
System.out.println(o.getClass().getName());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
// 传递方法名
objectOutputStream.writeUTF(method.getName());
//传递方法参数类型
objectOutputStream.writeObject(method.getParameterTypes());
//传递方法参数
objectOutputStream.writeObject(objects);
objectOutputStream.flush();
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
User user = (User) objectInputStream.readObject();
objectInputStream.close();
objectOutputStream.close();
socket.close();
return user;
}
};
try {
Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[]{IUserService.class}, invocationHandler);
return (IUserService) o;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
2.服务端
public class Server {
private static boolean flag = true;
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
while (flag){
Socket s = serverSocket.accept();
process(s);
s.close();
}
serverSocket.close();
}
/**
* 处理信息,返回数据
* @param s
* @throws IOException
*/
private static void process(Socket s) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ObjectInputStream objectInputStream = new ObjectInputStream(s.getInputStream());
// 传递过来的方法名称
String methodName = objectInputStream.readUTF();
// 传递过来的参数类型
Class[] parameterType = (Class[]) objectInputStream.readObject();
// 传递的参数数据
Object[] args = (Object[]) objectInputStream.readObject();
IUserService userService = new UserServiceImpl();
// 使用参数类型+参数+方法名 执行具体方法
Method method = userService.getClass().getMethod(methodName,parameterType);
User user = (User) method.invoke(userService, args);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(s.getOutputStream());
objectOutputStream.writeObject(user);
objectOutputStream.flush();
objectInputStream.close();
}
}
六·rpc-06
传递接口名称
1.添加公用
@Data
public class Student implements Serializable {
private Integer id;
private String studentName;
public Student() {
}
public Student(Integer id, String studentName) {
this.id = id;
this.studentName = studentName;
}
}
public interface IStudentService {
Student getStudentById(Integer id);
}
public class StudentServiceImpl implements IStudentService {
@Override
public Student getStudentById(Integer id) {
return new Student(id,"student_name");
}
}
2.客户端
public class Client {
public static void main(String[] args) {
IUserService sub = (IUserService)Stub.getStub(IUserService.class);
User userById = sub.getUserById(22222);
System.out.println(userById);
sub.run();
System.out.println("-----------------");
IStudentService stub = (IStudentService) Stub.getStub(IStudentService.class);
Student studentById = stub.getStudentById(789);
System.out.println(studentById);
}
}
public class Stub {
public static Object getStub(Class clazz){
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Socket socket = new Socket("127.0.0.1",8888);
System.out.println(clazz.getName());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
// 传递调用类名称
objectOutputStream.writeUTF(clazz.getName());
// 传递方法名
objectOutputStream.writeUTF(method.getName());
//传递方法参数类型
objectOutputStream.writeObject(method.getParameterTypes());
//传递方法参数
objectOutputStream.writeObject(objects);
objectOutputStream.flush();
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Object o1 = objectInputStream.readObject();
objectInputStream.close();
objectOutputStream.close();
socket.close();
return o1;
}
};
try {
Object o = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, invocationHandler);
return o;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
3.服务端
public class Server {
private static boolean flag = true;
private static Map<String, Class> mapClazz = Maps.newHashMap();
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
mapClazz.put("com.example.common.IUserService",UserServiceImpl.class);
mapClazz.put("com.example.common.IStudentService", StudentServiceImpl.class);
while (flag){
Socket s = serverSocket.accept();
process(s);
s.close();
}
serverSocket.close();
}
/**
* 处理信息,返回数据
* @param s
* @throws IOException
*/
private static void process(Socket s) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
ObjectInputStream objectInputStream = new ObjectInputStream(s.getInputStream());
// 传递过来的类名称
String clazzName = objectInputStream.readUTF();
// 传递过来的方法名称
String methodName = objectInputStream.readUTF();
// 传递过来的参数类型
Class[] parameterType = (Class[]) objectInputStream.readObject();
// 传递的参数数据
Object[] args = (Object[]) objectInputStream.readObject();
Class clazz = null;
// 从服务端注册表找到相应的具体类
// clazz = UserServiceImpl.class;
clazz = mapClazz.get(clazzName);
// 使用参数类型+参数+方法名 执行具体方法
Method method = clazz.getMethod(methodName, parameterType);
Object o = (Object) method.invoke(clazz.newInstance(), args);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(s.getOutputStream());
objectOutputStream.writeObject(o);
objectOutputStream.flush();
objectInputStream.close();
}
}
七·使用Hessian替代JDK自带序列化
/** * <dependency> * <groupId>com.caucho</groupId> * <artifactId>hessian</artifactId> * <version>4.0.60</version> * </dependency> */ public class HesianTest { public static void main(String[] args) throws Exception { User user = new User(1, "name"); byte[] serialize = serialize(user); System.out.println(serialize.length); byte[] serialize2 = serializeJDK(user); System.out.println(serialize2.length); User user1 = (User)deserialize(serialize); System.out.println(user1); } /** * 使用Hessian 反序列化 * @param serialize * @return * @throws Exception */ private static Object deserialize(byte[] serialize) throws Exception{ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serialize); Hessian2Input hessian2Input = new Hessian2Input(byteArrayInputStream); Object o = hessian2Input.readObject(); hessian2Input.close(); byteArrayInputStream.close(); return o ; } /** * 使用Hessian 序列化 * @param user * @return * @throws Exception */ private static byte[] serialize(User user) throws Exception { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Hessian2Output hessian2Output = new Hessian2Output(byteArrayOutputStream); hessian2Output.writeObject(user); hessian2Output.flush(); byte[] bytes = byteArrayOutputStream.toByteArray(); hessian2Output.close(); byteArrayOutputStream.close(); return bytes; } /** * 使用jdk 序列化 * @param user * @return * @throws Exception */ private static byte[] serializeJDK(User user) throws Exception { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(user); objectOutputStream.flush(); byte[] bytes = byteArrayOutputStream.toByteArray(); objectOutputStream.close(); byteArrayOutputStream.close(); return bytes; } }