远程调用-1

    xiaoxiao2022-07-12  155

    一、远程调用

    考试时不会,求救室友 自己有个方法不会实现,但是别人会实现,让别做的过程,就是远程调用

    1.1好处

    社会的分工

    二、实现调用

    Socket IO 流 反射

    2.1 实现流程

    2.2 室友的实现

    ServerSocket /** * 室友的实现 * @author CodeLab *1 室友打开手机+ 监听短信 *2 室友收到题目 *3 室友解析题目 *4 室友做答案 *5 室友做出来了,把答案发给你 */ public class ClassmateApp { public static void main(String[] args) throws Exception { //1室友打开手机+ 监听短信 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("手机打开了,开始等待。。。"); Socket socket = serverSocket.accept(); // 开始监听 System.out.println("菜逼的题目来了"); System.out.println("获取它的题目"); InputStream inputStream = socket.getInputStream(); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); String question = (String)objectInputStream.readObject(); // 1 + 1 System.out.println("接受到菜逼的题目为"+question); Integer result = 1 + 1 ; // 室友算出来 System.out.println("答案算出来了"); System.out.println("发送答案"); OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(result); System.out.println("答案发送成功"); // 关闭资源 close(objectOutputStream,outputStream,objectInputStream,inputStream,socket, serverSocket); } /** * 以后关闭流时,使用下面的操作 * 所有的流都实现了Closeable 接口 * @param claseables */ public static void close(Closeable ...claseables) { for (Closeable closeable : claseables) { if(null!=closeable) { try { closeable.close(); // 关闭时也可能发生异常 } catch (IOException e) { e.printStackTrace(); }finally { closeable = null ; // 但对象失去引用时,gc 会回收它 } } } } }

    2.2 自己的实现

    Sokcet

    /** * 自己考试的实现 * @author CodeLab *1 读题目,发现不会 *2 室友会这个题目 *3 把题目发生给室友 *4 接收室友的答案 *5 把答案抄上去 */ public class SlefApp { public static void main(String[] args) throws UnknownHostException, IOException, ClassNotFoundException { System.out.println("1 开始考试"); String question = "1 + 1 =?"; System.out.println("这个题目"+question+",不会,求救室友"); System.out.println("把题目发给室友"); Socket socket = new Socket("localhost", 8888); OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(question); System.out.println("题目发送完毕"); // 接收室友的答案 InputStream inputStream = socket.getInputStream(); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); Object answer = objectInputStream.readObject(); System.out.println("室友的答案接收完毕"); System.out.println("我写上去:1 +1 = "+answer); close(objectInputStream,inputStream,objectOutputStream, outputStream,socket); } /** * 以后关闭流时,使用下面的操作 * 所有的流都实现了Closeable 接口 * @param claseables */ public static void close(Closeable ...claseables) { for (Closeable closeable : claseables) { if(null!=closeable) { try { closeable.close(); // 关闭时也可能发生异常 } catch (IOException e) { e.printStackTrace(); }finally { closeable = null ; // 但对象失去引用时,gc 会回收它 } } } } }

    三、远程调用建模

    3.1 我

    服务的消费者

    3.2 室友

    服务的提供者,提供算出来1+1 = ? 答案

    3.3 调用的内容->某种服务

    1 +1 = ? 调用一个接口里面的方法

    3.4 题目

    3.5 答案

    四、实现该模型

    4.1 创建api 项目

    Api 里面非常简单,只有一个接口

    /** * 提供加法运算的接口 * @author CodeLab * */ public interface AddService { /** * 加法运行 * @param a * @param b * @return */ Integer add(Integer a,Integer b); Integer desc(Integer a,Integer b); }

    4.2 服务的消费者

    Maven 项目

    4.2.1 服务提供者实现api

    在pom.xml 文件里面依赖

    <dependencies> <dependency> <groupId>com.sxt</groupId> <artifactId>api</artifactId> <version>6.0</version> </dependency> </dependencies>

    实现接口

    public class AddServiceImpl implements AddService{ /** * 我作为服务的提供者,我知道他怎么做 */ @Override public Integer add(Integer a, Integer b) { return a + b; } @Override public Integer desc(Integer a, Integer b) { return a - b ; } }

    4.2.2 服务提供者监听端口

    public class ClassMateApp { public static void main(String[] args) { ServerSocket serverSocket = null ; try { serverSocket = new ServerSocket(8888); } catch (IOException e) { e.printStackTrace(); } while(true) { start(serverSocket); } } public static void start(ServerSocket serverSocket) { // 使用监听 try { System.out.println("开始监听菜逼的题目"); Socket socket = serverSocket.accept(); // 获取菜逼的题目 InputStream in = socket.getInputStream(); ObjectInputStream objectInputStream = new ObjectInputStream(in); Request request = (Request)objectInputStream.readObject(); // 反射调用得到题目的答案 Response answer = getAnswer(request); // 将答案发给菜逼 OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(answer); // 关闭资源的操作 closes(objectOutputStream,outputStream,objectInputStream,in,socket); } catch (Exception e) { e.printStackTrace(); } } public static void closes(Closeable ...closeables) { for (Closeable closeable : closeables) { if(null!=closeable) { try { closeable.close(); } catch (IOException e) { e.printStackTrace(); closeable = null ; } } } } private static Response getAnswer(Request request) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { // 题目获取完毕 String interfaceName = request.getInterfaceName(); String methodName = request.getMethodName(); Object[] args2 = request.getArgs(); Class<?> interfcs = Class.forName(interfaceName); // 获取到接口了 // 获取该接口的实现类对象 Object objectImpl = getImplClass(interfcs); Class<?>[] parameterTypes = new Class<?>[args2.length]; for (int i = 0; i < parameterTypes.length; i++) { parameterTypes[i] = args2[i].getClass(); // 获取参数的类型 } Method method = objectImpl.getClass().getMethod(methodName, parameterTypes); Object result = method.invoke(objectImpl, args2); // 将答案算出来 Response response = new Response(); response.setResult(result);// 包装答案 return response ; } private static Object getImplClass(Class<?> interfcs) { // AddService -》 AddServiceImpl // 通过接口获取它的实现类对象 return new AddServiceImpl(); } }

    4.3 服务的消费者

    4.3.1 服务消费者消费该接口

    Pom.xml依赖

    <dependencies> <dependency> <groupId>com.sxt</groupId> <artifactId>api</artifactId> <version>6.0</version> </dependency> </dependencies>

    调用:

    public class SelfConsumer { public static void main(String[] args) { System.out.println("我在考试"); System.out.println("有个题目 : 1 + 1= ? 不会"); System.out.println("求救室友"); AddService addServiceProxy = (AddService)ProxyObjectFactory.createProxy(AddService.class); // 这里的接口需要运行,需要一个代理对象 /** * 代理对象执行方法,进invoke 里面 */ Integer result = addServiceProxy.add(4, 6); // 体现我在调用这个接口,服务的消费者 System.out.println("答案已经获取到了"+result); Integer desc = addServiceProxy.desc(5, 1); System.out.println("答案已经获取到了"+desc); } }

    4.3.2 代理对象的调用细节

    /** * 给接口创建一个代理对象 * @author CodeLab * */ public class ProxyObjectFactory { /** * 给一个接口提供代理对象 * @param clazz * 接口 * @return * 代理对象 */ public static Object createProxy(Class<?> clazz) { return Proxy.newProxyInstance(ProxyObjectFactory.class.getClassLoader(), new Class<?>[] {clazz}, new InvocationHandler() { // 以后代理对象执行任何方法,都有进入 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 若在这里面实现了远程调用室友,则调用就可以完成 // TODO 如何在此实现对室友的调用 // 要调用我,必须告诉我你要调用那个对象(对象的名称即),你要调用这个对象里面的那个方法(方法的名称),还有这个方法的参数(args) //clazz.getName() : 接口名称 Response reps = rpc(new Request(clazz.getName(), method.getName(), args)); return reps.getResult(); } }); } /** * 向使用发生一个request 对象,得到使用的响应 * @param request * request * @return * response * 得到室友的响应 */ public static Response rpc(Request request) { Response response = null ; try { Socket socket = new Socket("localhost", 8888); OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(request);// 给室友把题目发送过去 // 接收室友的答案 InputStream inputStream = socket.getInputStream(); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); response = (Response)objectInputStream.readObject(); closes(objectInputStream,inputStream,objectOutputStream, outputStream,socket); } catch (Exception e) { e.printStackTrace(); } return response; } public static void closes(Closeable ...closeables) { for (Closeable closeable : closeables) { if(null!=closeable) { try { closeable.close(); } catch (IOException e) { e.printStackTrace(); closeable = null ; } } } } }

    五、引入负载均衡的概念

    从一个列表里面选一个出来的过程

    5.1 高并发

    一个使用慢不过来,又请了一个室友 调用太多,一个人忙不过来 如何在3 个室友里面选一个出来

    5.2 服务端的负载均衡

    类似nginx 的模式,由服务决定访问那个地址

    5.3 客户端的负载均衡

    5.4 使用客户端的负载均衡来调用不同的室友

    { Localhost:8888 Localhost:7777 Localhost:9999 }

    5.5 注册中心的引入

    5.6 室友的启动后需要注册自己

    5.7 我调用时,需要从注册中心拉取服务的列表

    5.8 注册中心该怎么做?

    Map<String,List> appCenter; { K: 服务名称, V:服务的地址 } Zookeeper 是最通用的注册中心

    最新回复(0)