基本实现思路
必须的角色
- provider服务提供
- consumer服务消费
- registry注册
- protocol协议
服务提供方
1、定义服务接口和实现类(接口
HelloService)
2、实现类
HelloServiceImpl
public interface HelloServer {
public String sayHello(String msg);
}
-------------------------------------------------
public class HelloServerImpl implements HelloServer {
@Override
public String sayHello(String msg) {
return msg+"调用了My_rpc的提供方服务";
}
}
3、服务注册:注册中心
此处注册中心我们将服务注册在
map集合中,结构:Map<String,Map<URL,Class>>
外边
map
的
key存储服务接口的全类名
,URL
封装了调用服务的
ip
和
port,
里边
value
指定指定具体实现类的全类名
4、启动服务:暴漏服务
------------------------------------注册中心----------------------------------
import java.util.HashMap;
import java.util.Map;
import com.lf.pojo.URL;
public class NativeRegistry {
/**
* 注册中心
*/
public static Map<String, Map<URL,Class>> registCenter=new HashMap<String, Map<URL,Class>>();
/**
* 注册服务
*/
public static <url> void regist(String name,URL url, Class implClass){
Map<URL,Class> map=new HashMap<URL,Class>();
map.put(url,implClass);
registCenter.put(name,map);
}
/**
* 获取服务
*/
public static Class get(String name, URL url){
Map<URL,Class> map=registCenter.get(name);
return map.get(url);
}
}
---------------------------URL类定义---------------------------------------
import java.util.Objects;
public class URL {
private String hostName;
private String port;
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public URL(String hostName, String port) {
this.hostName = hostName;
this.port = port;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
URL url = (URL) o;
return hostName.equals(url.hostName) &&
port.equals(url.port);
}
@Override
public int hashCode() {
return Objects.hash(hostName, port);
}
}
------------------------------启动服务提供类注册服务并暴露服务-----------------
import com.lf.HttpServer;
import com.lf.pojo.URL;
import com.lf.reistry.NativeRegistry;
import com.lf.server.HelloServer;
import com.lf.server.Impl.HelloServerImpl;
public class ServerProvider {
public static void main(String[] args) {
//注册服务
URL url=new URL("localhost","8080");
NativeRegistry.regist(HelloServer.class.getName(),url, HelloServerImpl.class);
//暴漏服务
HttpServer httpServer=new HttpServer();
httpServer.start(url.getHostName(),Integer.valueOf(url.getPort()));
}
}
-------------------、
protocol协议
服务之间调用的通信协议采用http协议,所以在服务provider中启动tomcat暴露服务
添加内嵌tomcat的依赖
--------------------
<dependencies>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.12</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
----------------------------------创建HttpServer-----------------------------------
import org.apache.catalina.*;
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;
public class HttpServer {
/*** tomcat服务启动 * 参考tomcat配置 * <Server port="8005" shutdown="SHUTDOWN"> * <Service name="Catalina"> * <Connector port="8080" protocol="HTTP/1.1" * connectionTimeout="20000" * redirectPort="8443" * URIEncoding="UTF-8"/> * <Engine name="Catalina" defaultHost="localhost"> * <Host name="localhost" appBase="webapps"*/
public void start(String hostname,Integer port){
// 实例一个tomcat
Tomcat tomcat = new Tomcat();
// 构建server
Server server = tomcat.getServer();
// 获取service
Service service = server.findService("Tomcat");
// 构建Connector
Connector connector = new Connector();
connector.setPort(port); connector.setURIEncoding("UTF-8");
// 构建Engine
Engine engine = new StandardEngine(); engine.setDefaultHost(hostname);
// 构建Host
Host host = new StandardHost(); host.setName(hostname);
// 构建Context
String contextPath = "";
Context context = new StandardContext();
context.setPath(contextPath); context.addLifecycleListener(new Tomcat.FixContextListener());
// 生命周期 监听器 然后按照server.xml,一层层把子节点添加到父节点
host.addChild(context);
engine.addChild(host);
service.setContainer(engine); service.addConnector(connector);
// service在getServer时就被添加到server节点了
// tomcat是一个servlet,设置路径与映射
tomcat.addServlet(contextPath,"dispatcher",new DispatcherServlet()); context.addServletMappingDecoded("/*","dispatcher");
try {
tomcat.start();
// 启动tomcat
tomcat.getServer().await();
// 接受请求
}catch (LifecycleException e){
e.printStackTrace();
}
}
}
---------------------------------------HttpServerHandler处理远程调用请求------------------
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DispatcherServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
new HttpServerHander().handler(req,resp);
}
}
import com.lf.pojo.Invocation;
import com.lf.pojo.URL;
import com.lf.reistry.NativeRegistry;
import org.apache.commons.io.IOUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
public class HttpServerHander {
public void handler(HttpServletRequest req, HttpServletResponse resp){
try{
// Http请求流转为对象
InputStream is = req.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
Invocation invocation = (Invocation)ois.readObject();
// 寻找注册中心的实现类,通过反射执行方法
Class implClass = NativeRegistry.get(invocation.getInterfaceName(),new URL("localhost","8080"));
Method method = implClass.getMethod(invocation.getMethodName(),invocation.getParamTypes());
String result = (String) method.invoke(implClass.newInstance(),invocation.getParams());
// 将结果返回
IOUtils.write(result,resp.getOutputStream());
}catch (Exception e){
e.printStackTrace();
}
}
}
-----------------------封装调用参数Invocation--------------
import java.io.Serializable;
public class Invocation implements Serializable {
private String interfaceName;
private String methodName;
private Object[] params;
private Class[] paramTypes;
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 Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
}
public Class[] getParamTypes() {
return paramTypes;
}
public void setParamTypes(Class[] paramTypes) {
this.paramTypes = paramTypes;
}
}
5、服务消费端
封装httpclent对象,发起远端调用
import com.lf.pojo.Invocation;
import com.lf.server.HelloServer;
public class ConsumerMain {
public static void main(String[] args) {
Invocation invocation=new Invocation(HelloServer.class.getName(),"sayHello",new Object[]{"myRPC客户端"},new Class[]{String.class});
Httpclient httpclient=new Httpclient();
String result =httpclient.post("localhost",8080,invocation);
System.out.println(result);
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class Httpclient {
public String post(String hostname, Integer port, Invocation invocation) {
try {
// 进行http连接
URL url = new URL("http",hostname,port,"/client/");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
// 必填项 // 将对象写入输出流
OutputStream os = connection.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(invocation);
oos.flush();
oos.close();
// 将输入流转为字符串(此处可是java对象)
InputStream is = connection.getInputStream();
return IOUtils.toString(is);
}catch (MalformedURLException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
return null;
}
}
public interface HelloServer {
public String sayHello(String msg);
}
import java.io.Serializable;
public class Invocation implements Serializable {
private String interfaceName;
private String methodName;
private Object[] params;
private Class[] paramTypes;
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 Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
}
public Class[] getParamTypes() {
return paramTypes;
}
public void setParamTypes(Class[] paramTypes) {
this.paramTypes = paramTypes;
}
public Invocation(String interfaceName, String methodName, Object[] params, Class[] paramTypes) {
this.interfaceName = interfaceName;
this.methodName = methodName;
this.params = params;
this.paramTypes = paramTypes;
}
}
执行结果