RPC
远程过程调用
服务提供者 将服务提供到注册中心,消费者从注册中心获取需要i调用的服务,去进行调用
模块创建
消费者(Consumer)
** pom **
java
<?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>
** 代码**
java
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 **
java
<?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>
** 代码 **
java
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 **
java
<?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 **
java
<?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
java
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
java
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 {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
new HttpServerHandler().handler(req,res);
}
}
HttpServerHandler
java
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(调用对象)
java
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(本地注册)
java
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对象
java
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请求
java
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(代理对象)
java
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() {
@Override
public 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 (模拟远程注册中心)
java
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;
}
}
简单的负载均衡
java
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);
}
}