RPC
远程过程调用
服务提供者 将服务提供到注册中心,消费者从注册中心获取需要i调用的服务,去进行调用
模块创建
消费者(Consumer)
** pom **
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>rpc01</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>Consumer</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.example</groupId><artifactId>ProviderCommon</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.example</groupId><artifactId>ycrpc</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
** 代码**
package com.yc;import com.yc.common.Invocation;
import com.yc.protocol.HttpClient;
import com.yc.proxy.ProxyFactory;/*** @Author yc* @PackageName yeb* @Package com.yc* @Date 2023/9/5 17:05*/
public class Consumer {public static void main(String[] args) {
// HelloService helloService = ProxyFactory.getProxy(HelloService.class);HelloService helloService = ProxyFactory.getProxy(HelloService.class);String result = helloService.sayHello("yc1111");System.out.println(result);}}
提供者(Provider)
** pom **
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>rpc01</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>Provider</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.example</groupId><artifactId>ProviderCommon</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.example</groupId><artifactId>ycrpc</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
</project>
** 代码 **
package com.yc;import com.yc.common.URL;
import com.yc.protocol.HttpServer;
import com.yc.register.LocalRegister;
import com.yc.register.MapRemoteRegister;/*** @Author yc* @PackageName yeb* @Package com.yc* @Date 2023/9/5 17:11*/
public class Provider {public static void main(String[] args) {LocalRegister.regist(HelloService.class.getName(),"1.0",HelloServiceImpl.class);
// LocalRegister.regist(HelloService.class.getName(),"1.0",HelloServiceImpl02.class);//注册中心注册,服务注册URL url = new URL("127.0.0.1",8181);MapRemoteRegister.regist(HelloService.class.getName(),url);HttpServer httpServer = new HttpServer();httpServer.start(url.getHostname(),url.getPort());}
}
ProviderCommon
** pom **
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>rpc01</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>ProviderCommon</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties></project>
rpc
** pom **
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>rpc01</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>ycrpc</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-core</artifactId><version>8.5.93</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-io</artifactId><version>1.3.2</version></dependency></dependencies></project>
启动tomcat
package com.yc.protocol;import org.apache.catalina.Server;
import org.apache.catalina.Service;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.startup.Tomcat;/*** @Author yc* @PackageName yeb* @Package com.yc.protocol* @Date 2023/9/5 17:20*/
public class HttpServer {public void start(String hostName,Integer prot ){Tomcat tomcat = new Tomcat();Server server = tomcat.getServer();Service service = server.findService("Tomcat");Connector connector = new Connector();connector.setPort(prot);StandardEngine engine = new StandardEngine();engine.setDefaultHost(hostName);StandardHost host = new StandardHost();host.setName(hostName);String contextPath="";StandardContext context = new StandardContext();context.setPath(contextPath);context.addLifecycleListener(new Tomcat.FixContextListener());host.addChild(context);engine.addChild(host);service.setContainer(engine);service.addConnector(connector);tomcat.addServlet(contextPath,"dispatcher",new DisPatcherServlet());context.addServletMappingDecoded("/*","dispatcher");try {tomcat.start();tomcat.getServer().await();} catch (Exception e) {e.printStackTrace();}}}
DisPatcherServlet
package com.yc.protocol;import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import java.io.IOException;/*** @Author yc* @PackageName rpc01* @Package com.yc.protocol* @Date 2023/9/6 14:09*/
public class DisPatcherServlet extends HttpServlet {@Overridepublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {new HttpServerHandler().handler(req,res);}
}
HttpServerHandler
package com.yc.protocol;import com.yc.common.Invocation;
import com.yc.register.LocalRegister;
import org.apache.commons.io.IOUtils;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;/*** @Author yc* @PackageName rpc01* @Package com.yc.protocol* @Date 2023/9/6 14:11*/
public class HttpServerHandler {public void handler(ServletRequest req, ServletResponse res) {// 处理请求 --》 接口、方法、方法参数try {Invocation invocation = (Invocation) new ObjectInputStream(req.getInputStream()).readObject();String interfaceName = invocation.getInterfaceName();Class classImpl = LocalRegister.get(interfaceName, "1.0");Method method = classImpl.getMethod(invocation.getMethodName(), invocation.getParameterTypes());String result = (String) method.invoke(classImpl.newInstance(), invocation.getParameters());IOUtils.write(result, res.getOutputStream());} catch (Exception e) {e.printStackTrace();}}
}
Invocation(调用对象)
package com.yc.common;import java.io.Serializable;/*** @Author yc* @PackageName rpc01* @Package com.yc.common* @Date 2023/9/6 14:13*/
public class Invocation implements Serializable {private String interfaceName; //接口名private String methodName; //方法名private Class[] parameterTypes;//参数类型private Object[] parameters;//参数public Invocation(String interfaceName, String methodName, Class[] parameterTypes, Object[] parameters) {this.interfaceName = interfaceName;this.methodName = methodName;this.parameterTypes = parameterTypes;this.parameters = parameters;}public String getInterfaceName() {return interfaceName;}public void setInterfaceName(String interfaceName) {this.interfaceName = interfaceName;}public String getMethodName() {return methodName;}public void setMethodName(String methodName) {this.methodName = methodName;}public Class[] getParameterTypes() {return parameterTypes;}public void setParameterTypes(Class[] parameterTypes) {this.parameterTypes = parameterTypes;}public Object[] getParameters() {return parameters;}public void setParameters(Object[] parameters) {this.parameters = parameters;}
}
LocalRegister(本地注册)
package com.yc.register;import java.util.HashMap;
import java.util.Map;/*** @Author yc* @PackageName rpc01* @Package com.yc.register* @Date 2023/9/6 14:19*/
public class LocalRegister {private static Map<String ,Class> map = new HashMap<>();public static void regist(String interfaceName ,String version ,Class implClass){map.put(interfaceName+version,implClass);}public static Class get(String interfaceName ,String version){return map.get(interfaceName+version);}
}
URL对象
package com.yc.common;import java.io.Serializable;/*** @Author yc* @PackageName rpc01* @Package com.yc.common* @Date 2023/9/6 15:11*/
public class URL implements Serializable {private String hostname;private Integer port;public URL(String hostname, Integer port) {this.hostname = hostname;this.port = port;}public String getHostname() {return hostname;}public void setHostname(String hostname) {this.hostname = hostname;}public Integer getPort() {return port;}public void setPort(Integer port) {this.port = port;}
}
发送http请求
package com.yc.protocol;import com.yc.common.Invocation;
import org.apache.commons.io.IOUtils;import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;/*** @Author yc* @PackageName rpc01* @Package com.yc.protocol* @Date 2023/9/6 14:39*/
public class HttpClient {public String send(String hostname, Integer port, Invocation invocation) throws Exception {try {URL url = new URL("http", hostname, port, "/");HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();httpURLConnection.setRequestMethod("POST");httpURLConnection.setDoOutput(true);//配置OutputStream outputStream = httpURLConnection.getOutputStream();ObjectOutputStream oss = new ObjectOutputStream(outputStream);oss.writeObject(invocation);oss.flush();oss.close();InputStream inputStream = httpURLConnection.getInputStream();String result = IOUtils.toString(inputStream);return result;} catch (Exception e) {e.printStackTrace();throw e;}}
}
ProxyFactory(代理对象)
package com.yc.proxy;import com.yc.common.Invocation;
import com.yc.common.URL;
import com.yc.loadbalance.Loadbalance;
import com.yc.protocol.HttpClient;
import com.yc.register.MapRemoteRegister;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;/*** @Author 杨超* @PackageName rpc01* @Package com.yc.proxy* @Date 2023/9/6 15:03*/
public class ProxyFactory {public static <T> T getProxy(Class interfaceClass) {Object proxyInstance = Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// String mock = System.getProperty("mock");
// if (mock != null && mock.startsWith("return:")) {
// String result = mock.replace("return:", "");
// return result;
// }Invocation invocation = new Invocation(interfaceClass.getName(), method.getName(),method.getParameterTypes(), args);HttpClient httpClient = new HttpClient();//服务发现List<URL> list = MapRemoteRegister.get(interfaceClass.getName());//服务调用String result = null;List<URL> invokedUrls = new ArrayList<>();int max = 5;while (max > 0) {//负载均衡list.remove(invokedUrls);URL url = Loadbalance.random(list);invokedUrls.add(url);try {result = httpClient.send(url.getHostname(), url.getPort(), invocation);return result;} catch (Exception e) {e.printStackTrace();if (max-- == 0) {continue;}// error-callback = com.yc.helloServiceErrorCallback//容错return "报错了";}}return result;}});return (T) proxyInstance;}}
MapRemoteRegister (模拟远程注册中心)
package com.yc.register;import com.yc.common.URL;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @Author yc* @PackageName rpc01* @Package com.yc.register* @Date 2023/9/6 15:12*/
public class MapRemoteRegister {private static Map<String, List<URL>> map = new HashMap<>();public static void regist(String interfaceName, URL url) {List<URL> list = map.get(interfaceName);if (list == null) {list = new ArrayList<>();}list.add(url);map.put(interfaceName, list);saveFile();}public static List<URL> get(String interfaceName) {map = getFile();return map.get(interfaceName);}private static void saveFile() {try {FileOutputStream fileOutputStream = new FileOutputStream("D:\\yc\\Java\\idea\\idea-work\\project\\rpc01\\temp.txt");ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);objectOutputStream.writeObject(map);} catch (Exception e) {e.printStackTrace();}}private static Map<String, List<URL>> getFile() {try {FileInputStream fileInputStream = new FileInputStream("D:\\yc\\Java\\idea\\idea-work\\project\\rpc01\\temp.txt");ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);return (Map<String, List<URL>>) objectInputStream.readObject();} catch (Exception e) {e.printStackTrace();}return null;}}
简单的负载均衡
package com.yc.loadbalance;import com.yc.common.URL;import javax.annotation.Resource;
import java.util.List;
import java.util.Random;/*** @Author 杨超* @PackageName rpc01* @Package com.yc.loadbalance* @Date 2023/9/6 15:19*/
public class Loadbalance {public static URL random(List<URL> urls){Random random = new Random();int i = random.nextInt(urls.size());return urls.get(i);}
}