RPC原理

1、Java代理模式

1.1 静态代理

​ 过程:

​ 1) 定义一个接口:ITeacherDao

​ 2) 目标对象 TeacherDAO 实现接口 ITeacherDAO

​ 3) 使用静态代理方式,就需要在代理对象 TeacherDAOProxy 中也实现 ITeacherDAO

​ 4) 调用的时候通过调用代理对象的方法来调用目标对象.

​ 5) 特别提醒:代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法

 public class Client {  

	public static void  main(String[] args) {  
		//创建目标对象(被代理对象)  
		TeacherDao teacherDao =  new TeacherDao();     
		//创建代理对象, 同时将被代理对象传递给代理对象  
		TeacherDaoProxy  teacherDaoProxy = new TeacherDaoProxy(teacherDao);     
		//通过代理对象,调用到被代理对象的方法  
		//即:执行的是代理对象的方法,代理对象再去调用目标对象的方法  
		teacherDaoProxy.teach();  
		}  
} 
//接口
public interface  ITeacherDao {     
	void teach(); // 授课的方法  
}  


//目标对象
public class TeacherDao  implements ITeacherDao { 

	@Override  public void teach() {  
		System.out.println(" 老师授课中。。。。。");  
	}        
} 

//代理对象,静态代理  
public class  TeacherDaoProxy implements ITeacherDao{  
	private ITeacherDao  target; // 目标对象,通过接口来聚合     
	//构造器  
	public TeacherDaoProxy(ITeacherDao target) {  
	this.target = target;  }        
	
	@Override  public void teach() {  
		System.out.println("开始代理  完成某些操作。。。。。 ");
		target.teach();  
		System.out.println("提交。。。。。");
  }  }  

1.2 动态代理

动态代理又叫 jdk代理、接口代理,主要两个相关类:

  • Proxy(java.lang.reflect包下的),主要负责管理和创建代理类的工作。
  • InvocationHandler 接口,只拥有一个invoke方法,主要负责方法调用部分,是动态代理中我们需要实现的方法
1.2.1 主要功能介绍

1、动态生成代理对象

使用Proxy.newProxyInstance方法

newProxyInstance(ClassLoader loader,//目标对象的类加载器
                 Class<?>[] interfaces,//目标对象实现的接口
                 InvocationHandler h)//目标对象方法被调用时的处理器

通过这个方法 生成动态代理对象 $Proxy.class

//将生成的代理对象输出到文件中,否则就在内存中直接使用
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

2、InvocationHandler 接口

class TestHandler implements InvocationHandler{

    @Override
    public Object invoke(Object proxy,//生成的代理对象 $Proxy0
                         Method method, //想要调用目标对象中的方法
                         Object[] args) //方法的参数列表
            throws Throwable {
        return null;
    }
}
1.2.2 代码实例

接口

public interface ITeacherDao {

    void teach(); 
    void sayHello(String name);
    
}

目标函数

public class TeacherDao implements ITeacherDao {


    @Override
    public void teach() {
        System.out.println(" 老师授课中.... ");
    }

    @Override
    public void sayHello(String name) {
        System.out.println("hello " + name);
    }


}

方法调用

public class Client {

    public static void main(String[] args) {
        TeacherDao teacherDao = new TeacherDao();

        //生成动态代理对象
        //System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        ITeacherDao m = (ITeacherDao)Proxy.newProxyInstance(
                //被代理对象的类加载器
                teacherDao.getClass().getClassLoader(),
                //被代理对象实现的接口类型
                new Class[]{ITeacherDao.class},
                // 被代理对象方法被调用时候的处理器
                new InvocationHandler() {

                    @Override// 生成的代理对象     调用被代理对象的方法   参数列表
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("method:" + method.getName() +" start...");
                        Object o = method.invoke(teacherDao,args);
                        System.out.println("method:" + method.getName() +" end!!...");
                        return o;
                    }
                });
        m.sayHello("小明");
    }


}
1.2.3 动态代理过程

在这里插入图片描述

​ 1、用Proxy.newProxyInstance 生成动态代理类 $Proxy0.class

​ 2、调用被代理对象的方法 m.sayHello(“小明”);

​ 进入$Proxy.sayHello()方法

 public final void sayHello(String var1) throws  {
        try {
        	//h  目标对象方法被调用时的处理器  InvocationHandler 
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

实际上调用了InvocationHandler中的invoke()方法,最终调用目标对象中的方法

生成的动态代理对象

public final class $Proxy0 extends Proxy implements ITeacherDao {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m4;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void sayHello(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void teach() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("test.ITeacherDao").getMethod("sayHello", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("test.ITeacherDao").getMethod("teach");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

2、RPC原理

2.1 流程

在这里插入图片描述

一次完整的RPC调用流程(同步调用)如下:

​ 1)服务消费方(client)调用以本地调用方式调用服务;

​ 2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
​ 3)client stub找到服务地址,并将消息发送到服务端;
​ 4)server stub收到消息后进行解码;
​ 5)server stub根据解码结果调用本地的服务;
​ 6)本地服务执行并将结果返回给server stub;
​ 7)server stub将返回结果打包成消息并发送至消费方;
​ 8)client stub接收到消息,并进行解码;
​ 9)服务消费方得到最终结果。

用到的知识有 动态代理,反射,序列化

2.2 代码

实体类、接口、方法

//实体类
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    int id;
    String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}


//接口
public interface IUserService {
    User findUserById(int id);
}


//实现方法
public class IProductServiceImpl implements IProductService{
    @Override
    public Product findProductByName(String name) {
        return new Product(1,name,1);
    }
}

client端

public class Client {
    public static void main(String[] args) {
        //调用远程服务的接口
        IUserService service = (IUserService)Stub.getStub(IUserService.class);
        System.out.println(service.findUserById(13));
    }
}

Stub

 static Object getStub(Class clazz){
     
        InvocationHandler h = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //调用服务端口
                Socket socket = new Socket("127.0.0.1",8088);
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

                String clazzName = clazz.getName();
                String methodName = method.getName();

                //将调用接口名、方法名、参数类型、参数写入
                oos.writeUTF(clazzName);
                oos.writeUTF(methodName);
                oos.writeObject(method.getParameterTypes());
                oos.writeObject(args);
                oos.flush();

                //接收服务端返回的结果,object读入
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                Object object =ois.readObject();

                return object;
            }
        };

        Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[]{IUserService.class}, h);
        
        return  o;
    }

server端

public class Server {
    private static boolean running = true;
    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(8088);
        while(running){
            Socket client = server.accept();
            process(client);
            client.close();
        }
        server.close();
    }
    public static void process(Socket socket) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());


        //将调用接口,方法,参数类型,参数解析出来
        String clazzName = ois.readUTF();
        String methodName = ois.readUTF();
        Class[] parameterTypes = (Class[]) ois.readObject();
        Object[] parameters = (Object[]) ois.readObject();

        Class clazz = IUserServiceImpl.class;
        //调用目标方法
        Method method = clazz.getMethod(methodName, parameterTypes);
        Object o = method.invoke(clazz.newInstance(), parameters);
        oos.writeObject(o);
        oos.flush();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值