dubbo模拟框架的自我搭建一
rpc:远程方法调用
框架实现思路:
1.提供一个服务得接口
2.提供服务得实现类
3.将服务注册到注册中心,将服务注册到本地
4.使用tomcat处理请求
整体流程图:
说明:
1.服务消费者向远程注册中心获取服务提供者的url
2.通过url连接服务提供者
3.服务提供者通过服务消费者提供的参数(包括执行参数,执行方法,接口名等)去本地注册中找实现方法执行,并返回执行结果
限制与优化:
限制:因为本项目没有连接第三方,如redis,zk。所以采用了对象刷磁盘来达到数据同步
优化:服务消费者向远程注册中心获取服务提供者的url时可以使用代理模式来代理每次需要传递的执行方法,执行参数等。
项目接口预览:
一:引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>4.5.11</version>
</dependency>
二.编写服务提供者Provider
public class Provider {
public static void main(String[] args) {
// 1.提供服务接口
// 2.提供实现类
// 3.注册服务(注册中心注册,本地注册)
//注册中心注册
URL url = new URL("127.0.0.1", 8081);
RemoteMapRegister.regist(HelloService.class.getName(),url);
//本地注册 接口名字:实现类
LocalMapRegister.regist(HelloService.class.getName(), HelloServiceImpl.class);
// 4.暴露服务(启动tomcat ,nettyServer,接收处理请求)
//启动tomcat
HttpServer httpServer = new HttpServer();
httpServer.start(url.getHostName(), url.getPort());
}
}
1.url
public class URL implements Serializable {
private String hostName;
private Integer port;
public URL(String hostName, Integer port) {
this.hostName = hostName;
this.port = port;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public void setPort(Integer port) {
this.port = port;
}
public String getHostName() {
return hostName;
}
public Integer getPort() {
return port;
}
}
2.服务中心注册 RemoteMapRegister.的regist,get
/**
* readFile,saveFile 是为了保证资源在两个jvm中能读到,实际开发可以用redis,zk
*/
public class RemoteMapRegister {
private static Map<String, List<URL>> REGISTER=new HashMap<>();
public static void regist(String interfance, URL url) {
List<URL> urls = REGISTER.get(interfance);
if (urls == null) {
urls = new ArrayList<>();
}
urls.add(url);
REGISTER.put(interfance,urls);
saveFile();
}
public static List<URL> get(String interfance){
if(REGISTER.size()==0){
REGISTER=readFile();
}
return REGISTER.get(interfance);
}
private static void saveFile(){
try {
FileOutputStream fileOutputStream = new FileOutputStream("/temp.text");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(REGISTER);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static Map<String,List<URL>> readFile(){
try {
FileInputStream fileInputStream = new FileInputStream("/temp.text");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
return (Map<String, List<URL>>) objectInputStream.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
3.本地注册 LocalMapRegister.regist
public class LocalMapRegister {
private static Map<String, Class> LOCAL_REGISTER=new HashMap<>();
public static void regist(String interfance, Class implClass) {
LOCAL_REGISTER.put(interfance,implClass);
}
public static Class get(String interfance){
return LOCAL_REGISTER.get(interfance);
}
4.httpServer.start启动tomcat,接收处理请求
public class HttpServer {
public void start(String hostName,Integer port){
Tomcat tomcat = new Tomcat();
Server server = tomcat.getServer();
Service service = server.findService("Tomcat");
Connector connector = new Connector();
connector.setPort(port);
Engine engine=new StandardEngine();
engine.setDefaultHost(hostName);
Host host=new StandardHost();
host.setName(hostName);
String contextPath="";
Context 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 DispathcherServlet());
context.addServletMappingDecoded("/*","dispatcher");
try {
tomcat.start();
tomcat.getServer().await();
}catch (LifecycleException e){
e.printStackTrace();
}
}
}
5.DispathcherServlet分发请求处理
public class DispathcherServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
new HeepServlerHandler().handler(req,resp);
}
}
public class HeepServlerHandler {
public void handler(HttpServletRequest req, HttpServletResponse resp){
try {
Invocation invocation = JSONObject.parseObject(req.getInputStream(), Invocation.class);
String interfaceName = invocation.getInterfaceName();
Class implClass = LocalMapRegister.get(interfaceName);
Method method = implClass.getMethod(invocation.getMethodName(), invocation.getParamType());
String result = (String) method.invoke(implClass.newInstance(), invocation.getParams());
IOUtils.write(result,resp.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
三:编写服务消费者Consumer
public class Consumer {
public static void main(String[] args) {
HelloService helloService = ProxyFactory.getProxy(HelloService.class);
String result = helloService.sayHello("123456");
System.out.println(result);
}
}
创建代理工厂ProxyFactory
public class ProxyFactory {
public static <T> T getProxy(final Class interfaceClass){
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
HttpClient httpClient = new HttpClient();
Invocation invocation = new Invocation(interfaceClass.getName(),method.getName(),method.getParameterTypes(),args);
List<URL> urls =RemoteMapRegister.get(interfaceClass.getName());
//负载均衡,拿一个可用得
Integer index= RandomUtil.randomInt(urls.size());
URL url =urls.get(index);
String result = httpClient.post(url.getHostName(), url.getPort(), invocation);
return result;
}
});
}
}
发送请求
public class HttpClient {
public String post(String hostName, Integer port, Invocation invocation){
try {
URL url = new URL("http", hostName, port, "/");
String post = HttpUtil.post(url.toString(), JSONObject.toJSONString(invocation));
return post;
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
}
测试:启动服务提供者provider ,消费者consumer