- dubbo
参考大神的dubbo面试的18问:https://blog.csdn.net/weixin_44337261/article/details/88149072
- dubbo是什么
Dubbo是阿里巴巴SOA服务化治理方案的核心框架,Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。 - dubbo架构
1.当服务的提供者启动时,会将服务的名称:IP:端口会写入注册中心.
2.注册中心内部会维护服务列表,某个服务提供者关机了,服务还能正常进行
3.当消费者需要访问服务时,需要先访问注册中心获取服务列表信息.之后将服务列表保存到本地缓存中.方便后续的访问.在客户端内部有负载均衡的算法,筛选出一台服务器,之后进行访问.
4.如果后台服务器出现宕机现象.这时注册中心通过心跳检测的方式判断服务器是否宕机.如果服务器宕机则会将该服务器信息从服务列表中删除.之后将新的服务列表发送消费者(客户端)进行更新. - dubbo底层原理
总结:RPC调用的规则可以传输java对象.底层实现时将数据转化流,并且该流经过加密处理.并且rpc内部使用UTF-8编码格式
要求:传输的java对象必须序列化
设计:
实现一个RPC远程调用框架
提供者:
public class ProviderMain {
public static void main(String[] args) {
try {
System.out.println("start server 20881");
ServerSocket serverSocket = new ServerSocket(20881);
while (true) {
ObjectInputStream objectInputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
Socket socket = serverSocket.accept();
// 1,接收数据
InputStream inputStream = socket.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
String interfaceName = objectInputStream.readUTF();
String methodName = objectInputStream.readUTF();
Class[] parameterTypes = (Class[]) objectInputStream.readObject();
Object[] argments = (Object[]) objectInputStream.readObject();
// 2,执行方法
// 根据interfaceName找到实现类
// map(interfaceName,impl);
Class implClass = CartServiceImpl.class;
Object implObject = implClass.newInstance();
Method method = implClass.getMethod(methodName, parameterTypes);
Object result = method.invoke(implObject, argments);
// 3,返回数据
OutputStream outputStream = socket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
objectInputStream.close();
objectOutputStream.close();
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
消费者:
public class CartController {
public static void main(String[] args) {
try {
Object object = getObject(CartService.class);
CartService cartService = (CartService) object;
cartService.findCartByUserId(91L);
} catch (Exception e) {
e.printStackTrace();
}
}
static class MyInvocationHandler implements InvocationHandler {
String interfaceName;
public MyInvocationHandler(String interfaceName) {
super();
this.interfaceName = interfaceName;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
try {
// 1,得方法名,参数数据
String methodName = method.getName();
Class[] parameterTypes = method.getParameterTypes();
// 2,发送数据
Socket socket = new Socket("127.0.0.1", 20881);
OutputStream outputStream = socket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeUTF(interfaceName);
objectOutputStream.writeUTF(methodName);
objectOutputStream.writeObject(parameterTypes);
objectOutputStream.writeObject(args);
// 3,接收数据
InputStream inputStream = socket.getInputStream();
objectInputStream = new ObjectInputStream(inputStream);
Object result = objectInputStream.readObject();
System.out.println("收到远程方法执行结果" + result);
return result;
} catch (Exception e) {
e.printStackTrace();
} finally {
objectOutputStream.close();
objectInputStream.close();
}
return null;
}
}
public static Object getObject(final Class interfaceInfo) {
// 1.将本地的接口调用转换成JDK的动态代理,在动态代理中实现接口的远程调用
String interfaceName = interfaceInfo.getName();
ClassLoader classLoader = interfaceInfo.getClassLoader();
Class[] interfaces = { interfaceInfo };
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(interfaceName);
Object object = Proxy.newProxyInstance(classLoader, interfaces, myInvocationHandler);
return object;
}
}
- 运用
提供者:
<?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="provider-of-cart"/>
<!-- 2,设置服务注册中心zookeeper地址 -->
<dubbo:registry address="zookeeper://192.168.216.202:2181">
</dubbo:registry>
<!-- 3,设置dubbo端口号 -->
<dubbo:protocol name="dubbo" port="20883"></dubbo:protocol>
<!-- 4,注册服务实现类对象-->
<bean class="com.jt.service.CartServiceImpl" id="cartService">
</bean>
<!-- 5,设置客户端能访问接口,像servlet注册-->
<dubbo:service interface="com.jt.service.CartService" ref="cartService">
</dubbo:service>
</beans>
注册中心、dubbo端口、注册服务实现类、客户端服务访问接口
服务消费者:
<?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.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
<!--1,设置应用名-->
<dubbo:application name="consumer-of-cart" />
<!--2,设置注册中心地址 -->
<dubbo:registry address="zookeeper://192.168.216.202:2181" />
<!--3,得到远程服务代理对象,可以像使用本地bean一样使用cartService -->
<dubbo:reference timeout="50000" id="cartService" interface="com.jt.cart.service.CartService" />
注册中心地址,访问接口名
- 面试问题
1、一般在项目中需要先启动服务提供者,后启动服务消费者,否则会报错,解决办法:
如:a,b 消费b , b也需要消费a中间的service.
启动时检查提供者是否存在,true报错,false忽略 不检查
@Configuration
public class DubboConfig {
/**
* 消费者配置不主动监督zookeeper服务
*
* @return
*/
@Bean
public ConsumerConfig consumerConfig() {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setCheck(false);
consumerConfig.setTimeout(40000);
return consumerConfig;
}
}
2、说明:当zk如果宕机后,消费者能否正确消息?????关zk,provider1,provider2
答案:可以
因为zk会动态的向客户端更新服务列表信息.当zk宕机后,由于之前已经同步了zk的服务列表信息,所以客户端可以 按照自己已经缓存的清单进行访问.如果在这个期间服务端程序发现宕机现象,那么则访问故障机时由于不能通信,则等待超时时间,则访问下一台服务器.
如果这时,所有的服务端程序都宕机,则整个服务陷入瘫痪.