dubbo学习笔记

dubbo学习笔记(小白,有错请指出谢谢)

简述

dubbo(阿里巴巴出品,之前开源,阿里巴巴不提供维护,但后来由于使用广泛,阿里又重新开始维护)是一个用来跨网络访问另外一台服务器的技术(RPC),在我看来,其实是对httpClient的一种封装,是调用者可以更加快捷方便,常用于微服务,dubbo中有服务的提供者、服务的消费者,其中消费者是通过调用接口,来获得服务,更大程度的解藕,服务的提供者类似于ssm框架中的serviceImpl,接口类似于service,消费者类似于controller。

官方给的整体模型

1、各点说明:

  • Provider: 服务的提供者(serviceImpl)。
  • Consumer: 消费者(controller)。
  • Registry: 注册中心(中间站)。
  • Monitor: 监控中心(统计服务调用次数和时间)
  • Container: 服务运行容器

2、调用关系说明:

  • 服务容器负责启动,加载,运行服务提供者。
  • 服务提供者在启动时,向注册中心注册自己提供的服务。
  • 服务消费者在启动时,向注册中心订阅自己所需的服务。
  • 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接(http中/1.1以后使用的,用于保持连接性,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,响应头中会加入Connection:keep-alive)推送变更数据给消费者。
  • 服务消费者,从提供者地址列表中,基于软负载均衡算法(轮询,随机,哈希,最快响应,最小并发),选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

大概了解了dubbo中几个关键的组件和调用过程后,来通过手写一个dubbo进行更深入了解

手写dubbo


Client为服务的消费者
infterface为中间的接口
Server为服务的提供者

package com.jt.cjt.service;

public interface CartService {
	public String findCartById(Long id);
}
package com.jt.cjt.service;

public class CartServiceImpl implements CartService {

	@Override
	public String findCartById(Long id) {
		return "cart";
	}

}
package com.jt.cjt.service;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;

public class MyDubboServer {
	
	public static void main(String[] args) {
		try {
			//监听9000端口号
			ServerSocket serverSocket = new ServerSocket(9000);
			System.out.println("启动服务器");
			while(true) {
				//接收用户的请求
				Socket socket = serverSocket.accept();
				InputStream inputStream = socket.getInputStream();
				ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
				//读取接口名
				String interfaceName = objectInputStream.readUTF();
				//读取方法名
				String methodName = objectInputStream.readUTF();
				//读取参数类型
				Class[] type = (Class[])objectInputStream.readObject();
				//读取参数
				Object[] p = (Object[])objectInputStream.readObject();
				//通过反射执行方法
					//根据接口找到实现类
				Class implClassInfo = CartServiceImpl.class;
				//通过反射创建对象
				Object implObject = implClassInfo.newInstance();
				//通过反射执行方法
				Method method = implClassInfo.getMethod(methodName, type);
				Object result = method.invoke(implObject, p);
				//把执行结果返回给客户端
				OutputStream outOutputStream = socket.getOutputStream();
				ObjectOutputStream objectOutputStream = new ObjectOutputStream(outOutputStream);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}
package com.jt.cjt.myDubboClient;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

import com.jt.cjt.service.CartService;

public class CartController {
	
	public static void main(String[] args) {
		//1,得到动态代理对象
		Object proxyObject=getProxyObject(CartService.class);
		//2,通过动态代理对象调用目标方法
		CartService cartService=(CartService)proxyObject;
		cartService.findCartById(100L);
		//3,调了目标方法,java虚拟机会执行invoke()
				
	}
	//内部类
	static class MyInvocationHandler implements InvocationHandler{
		
		String interfaceName;
		
		public MyInvocationHandler(String interfaceName) {
			super();
			this.interfaceName = interfaceName;
		}
		//由java虚拟机自动调用invoke
		public Object invoke(Object proxy,Method method, Object[] args) throws Throwable {
			//spring框架调@before的方法,调method
			//System.out.println(method.getName());
			try {
				//建立和服务器连接
				Socket socket = new Socket("127.0.0.1",9000);
				//发送接口名
				OutputStream outputStream = socket.getOutputStream();
				ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
				objectOutputStream.writeUTF(interfaceName);
				//发送方法名
				objectOutputStream.writeUTF(method.getName());
				//发送参数类型
				objectOutputStream.writeObject(method.getParameterTypes());
				//发送参数
				objectOutputStream.writeObject(args);
				//接收服务器结果
				InputStream inputStream = socket.getInputStream();
				ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
				Object serverReturnResult = objectInputStream.readObject();
				System.out.println(serverReturnResult);
			} catch (Exception e) {
				e.printStackTrace();
			}
			//System.out.println(args[0]);
			//联网发送方法名,参数
			return null;
		}
	}
	//返回代理对象
	static Object getProxyObject(Class interfaceInfo) {
		//类加载器作用加载类
		ClassLoader classLoader = interfaceInfo.getClassLoader();
		//动态代理对象根据动态类创建
		//普通类 在虚拟机看来就是字符串class 类名{方法}
		//动态类有一个接口,通过反射得到接口中的方法 class 类名{findCartById()}
		//放的类信息,有方法信息,根据方法创建动态类
		Class[] methodInfo={interfaceInfo};
		MyInvocationHandler myInvocationHandler = new MyInvocationHandler(interfaceInfo.getName());
		//java中实现动态代理是用proxy.newProxyInstance
		return Proxy.newProxyInstance(classLoader,methodInfo, myInvocationHandler);
	}
}

调用顺序
getProxyObject(CartService.class)获得CartService接口的代理对象–>调用代理对象接口中的方法,根据动态代理的执行顺序,会在执行方法前,先执行invoke方法,其中将接口名,方法名,参数类型,参数发送过去,在server中接收接口名,方法名,参数类型,参数,然后通过反射创建对象,执行方法,并将结果返回给server,接着server
接收返回结果

dubbo中的注册中心

注册中心有很多,在这里我们来说下zookeeper

zookeeper官方介绍

  • ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
  • ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户
  • ZooKeeper包含一个简单的原语集, [1] 提供Java和C的接口。
  • ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在zookeeper-3.4.3\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本

在这里不做深入讨论,简单描述下,在配置好zookeeper后(我是在linux上部署的,具体部署步骤可自行百度),通过客户端可进行查看,其中有服务的提供者信息,服务的消费者信息,并且根据权重自行进行轮询,可手动更改权重大小,来使请求更多的发送到配置较好的服务器上,zookeeper在本地会有缓存,所以当zookeeper服务宕机后,消费者仍可以获得提供者的服务,zookeeper是cp原则(CAP原则,分布式设计原则,c为一致性,a为可用性,p为分区容错性,其中p是必须实现的原则),这点跟eureka不同,eureka是ap原则(具体区别将在后续中进行讨论),zookeeper是基于心跳检测机制来查看服务是否还在运行,由于它的一致性,所以当有服务宕机时,在列表中会立即删除该服务

dubbo+zookeeper整合

首先先导入dubbo和zookeeper所需要的jar包(这里不做展示)
在这里插入图片描述

  • consumer:消费者
  • interface:接口
  • provider1:提供者1
  • provider2:提供者2
package com.jt.cjt.cart.service;

public interface CartService {
	public String findCartById(Long userId);
}
package com.jt.cjt.cart.service;

public class CartServiceImpl implements CartService{

	@Override
	public String findCartById(Long userId) {
		return "第一个提供着:cart";
	}

}
package com.jt.cjt.dubboProvider1;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
    	try {
    		System.out.println("提供者1开始");
    		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-provider.xml");
			context.start();
			System.out.println("提供者1启动");
			while(true)
			{
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://code.alibabatech.com/schema/dubbo 
	http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
	<!-- 微服务提供者配置文件,作用是把提供者的端口,实现类信息发给服务注册中心zookeeper -->
	<!-- 1,设置应用(微服务)名称 -->
	<dubbo:application name="provider1-of-cart"/>
	
	<!-- 2,设置zookeeper的ip地址和端口号 -->
	<dubbo:registry timeout="超时时间" address="zookeeper://IP地址:端口号">
	</dubbo:registry>
	
	<!-- 3,设置微服务的端口号 -->
	<dubbo:protocol port="端口号" name="dubbo"></dubbo:protocol>
	
	<!-- 4,设置实现类 -->
	<bean id="CartServiceImpl" class="com.jt.cjt.cart.service.CartServiceImpl">
	</bean>
	<!-- 5,设置客户端访问服务的地址,地址是接口名 -->
	<dubbo:service timeout="900000" interface="com.jt.cjt.cart.service.CartService" ref="CartServiceImpl">
	</dubbo:service>
	

</beans>
package com.jt.cjt.dubboConsumer;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.jt.cjt.cart.service.CartService;

public class CartController {
	public static void main(String[] args) {
		
		try {
			//启动spring框架
			ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-consumer.xml");
			//从spring框架取cartService对象
			//以前是从spring容器中取对象,对象是当前项目实现类的对象
			//用了dubbo,加了<refrence 指定了接口名CartService>
			//1,连接zookeeper,得到提供者信息
			//2,网络连接一个提供者,由提供者执行实现类,返回结果
			CartService cartService = (CartService)context.getBean("cartService");
			//调用提供者
			while(true)
			{
				String cart=cartService.findCartById(90L);
				System.out.println("消费者:"+cart);
				Thread.currentThread().sleep(1000);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://code.alibabatech.com/schema/dubbo 
	http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
	<!-- 1,设置应用(微服务)名称 -->
	<dubbo:application name="consumer-of-cart"/>
	
	<!-- 2,设置zookeeper的ip地址和端口号 -->
	<dubbo:registry timeout="900000" address="zookeeper://ip:port">
	</dubbo:registry>
	<!-- 3,那个接口的对象由dubbo管理 check=false 消费者启动时不会检查提供者是否启动 -->
	<!-- cartController @autowired CartService cartservice -->
	<dubbo:reference timeout="90000" check="false" id="cartService" interface="com.jt.cjt.cart.service.CartService">
	</dubbo:reference>
</beans>

下面为duubo和其他技术整合的示意图

duubo+zookeeper
在这里插入图片描述

dubbo+zookeeper+nginx+mycat
在这里插入图片描述

dubbo+zookeeper+nginx+redis+mycat
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值