讲解dubbo启动服务的时候先来了解下java的spi机制
1,dubbo的服务端的spring xml文件在dubbo的源码中默认在META-INF/spring上,它会自动在这个目录加载,也可在dubbo.properties配置
2,dubbo的容器启动是基于spi原理的,所以实现了一个接口的子类,在dubbo的加载器加载下会对其所有子类生成代理实例,然后一个一个遍历使用
3,微服务是基于独立功能模块来说,分层是基于每个微服务的接口(消费端-服务端)
一:SPI 简介
SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。 目前有不少框架用它来做服务的扩展发现, 简单来说,它就是一种动态替换发现的机制, 举个例子来说, 有个接口,想运行时动态的给它添加实现,你只需要添加一个实现,而后,把新加的实现,描述给JDK知道就行啦(通过改一个文本文件即可) ,公司内部目前Dubbo框架就基于SPI机制提供扩展功能。
代码例子
public interface Cmand { public void execute(); } public class ShutdownCommand implements Cmand { public void execute() { System.out.println("shutdown...."); } } public class StartCommand implements Cmand { public void execute() { System.out.println("start...."); } } public class SPIMain { public static void main(String[] args) { ServiceLoader<Cmand> loader = ServiceLoader.load(Cmand.class); System.out.println(loader); for (Cmand Cmand : loader) { Cmand.execute(); } } }
配置:
com.unei.serviceloader.impl.ShutdownCommand
com.unei.serviceloader.impl.StartCommand
运行结果:
java.util.ServiceLoader[com.unei.serviceloader.Cmand] shutdown.... start....
相关原理解答
1.配置文件为什么要放在META-INF/services下面?
ServiceLoader类定义如下:
private static final String PREFIX = "META-INF/services/"; (JDK已经写死了)
但是如果ServiceLoader在load时提供Classloader,则可以从其他的目录读取。
2.ServiceLoader读取实现类是什么时候实例化的?
public void reload() { providers.clear(); lookupIterator = new LazyIterator(service, loader); } private ServiceLoader(Class<S> svc, ClassLoader cl) { service = Objects.requireNonNull(svc, "Service interface cannot be null"); loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl; acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; reload(); }
二:dubbo服务启动之Container
Dubbo的总体架构如下图所示:
1:dubbo几大角色
Provider: 暴露服务的服务提供方。
Consumer: 调用远程服务的服务消费方。
Registry: 服务注册与发现的注册中心。
Monitor: 统计服务的调用次调和调用时间的监控中心。
Container: 服务运行容器。
2:Container详解
Dubbo的Container详解模块,是一个独立的容器,因为服务通常不需要Tomcat/JBoss等Web容器的特性,没必要用Web容器去加载服务。
服务容器只是一个简单的Main方法,并加载一个简单的Spring容器,用于暴露服务。
com.alibaba.dubbo.container.Main 是服务启动的主类
通过图可以了解Container接口有只有 start() stop()他的实现类
他的实现类有SpringContainer、Log4jContainer、JettyContainer、JavaConfigContainer、LogbackContainer。
当然你也可以自定义容器
官网:http://dubbo.io/Developer+Guide.htm#DeveloperGuide-ContainerSPI
Spring Container
自动加载META-INF/spring目录下的所有Spring配置。 (这个在源码里面已经写死了DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml" 所以服务端的主配置放到META-INF/spring/这个目录下)
配置:(配在java命令-D参数或者dubbo.properties中)
dubbo.spring.config=classpath*:META-INF/spring/*.xml ----配置spring配置加载位置Container
Jetty Container
启动一个内嵌Jetty,用于汇报状态。
配置:(配在java命令-D参数或者dubbo.properties中)
dubbo.jetty.port=8080 ----配置jetty启动端口
dubbo.jetty.directory=/foo/bar ----配置可通过jetty直接访问的目录,用于存放静态文件
dubbo.jetty.page=log,status,system ----配置显示的页面,缺省加载所有页面
Log4j Container
自动配置log4j的配置,在多进程启动时,自动给日志文件按进程分目录。
配置:(配在java命令-D参数或者dubbo.properties中)
dubbo.log4j.file=/foo/bar.log ----配置日志文件路径
dubbo.log4j.level=WARN ----配置日志级别
dubbo.log4j.subdirectory=20880 ----配置日志子目录,用于多进程启动,避免冲突
3:容器启动
从上面的我们知道只需执行main方法就能启动服务,那么默认到底是调用那个容器呢?
查看com.alibaba.dubbo.container.Container接口我们发现他上面有一个注解@SPI("spring")
通过上面对SPI的了解我们猜想他应该有对应的文件 如图:
通过上图可以知道默认调用的是com.alibaba.dubbo.container.spring.SpringContainer
这里main方法里面dubbo他们自定义了一个loader,叫ExtensionLoader
所以目前启动容器的时候我们可以选:spring、javaconfig、jetty、log4j、logback等参数
4:容器停止
Dubbo是通过JDK的ShutdownHook来完成优雅停机的,所以如果用户使用"kill -9 PID"等强制关闭指令,是不会执行优雅停机的,只有通过"kill PID"时,才会执行。
停止源码(在Main方法里面):
if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { for (Container container : containers) { try { container.stop(); logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!"); } catch (Throwable t) { logger.error(t.getMessage(), t); } synchronized (Main.class) { running = false; Main.class.notify(); } } } }); }
原理:
服务提供方
停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。
然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。
服务消费方
停止时,不再发起新的调用请求,所有新的调用在客户端即报错。
然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。
5:服务jar打包
我这里用到了maven打,在pom文件里面添加以下内容
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib</classpathPrefix>
<mainClass>com.alibaba.dubbo.container.Main</mainClass>
<useUniqueVersions>false</useUniqueVersions>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>pre-package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.demo.dubbox.service</groupId>
<artifactId>demo_order_api</artifactId>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWrite>true</overWrite>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<targetPath>${project.build.directory}/classes</targetPath>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<targetPath>${project.build.directory}/classes/META-INF/spring</targetPath>
<directory>src/main/resources/</directory>
<filtering>true</filtering>
<!-- 这个是主配置,把他打包到META-INF/spring/ 其他的xml都在spring-all.xml里面包含了 当然名字自定义-->
<includes>
<include>spring-all.xml</include>
</includes>
</resource>
</resources>
</build>
6:简单启动脚本
#!/bin/sh JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home JAVA_OPTS="-Xms256m -Xmx512m" java -jar XXX.jar > "log.log" 2>&1
相关推荐
Dubbo的核心组件包括服务提供者(Provider)、服务消费者(Consumer)、注册中心(Registry)、监控中心(Monitor)和服务容器(Container)。其设计原则主要体现在以下几个方面: 1. **服务化**:Dubbo将复杂的...
6. `dubbo-container`:Dubbo支持的容器,如Spring Container,用于启动和管理Dubbo服务。 7. `dubbo-spi`:Dubbo的扩展机制,基于Java SPI(Service Provider Interface)实现,允许用户自定义实现Dubbo的组件。 ...
- **Container(容器)**:可以理解为应用容器,用来装载服务提供者或消费者的程序。 #### 三、Dubbo的分布式系统架构 - **分布式架构设计原则**:包括服务拆分、服务组合、服务版本控制、服务限流降级等关键设计思想...
- Container:服务容器,如Spring容器 6. **Dubbo的注册与发现流程** - 服务提供者启动时,向注册中心注册服务 - 服务消费者从注册中心获取服务提供者的地址列表 - 消费者根据负载均衡策略选择一个服务提供者...
8. `dubbo-container`:提供了Spring、Jetty等容器的集成,方便部署和运行dubbo应用。 通过研究这些源码,开发者可以了解到dubbo是如何实现服务治理的,以及如何在实际项目中灵活应用。同时,对于想要深入学习...
* 服务容器Container负责启动,加载,运行服务提供者。 * 服务提供者Provider在启动时,向注册中心注册自己提供的服务。 * 服务消费者Consumer在启动时,向注册中心订阅自己所需的服务。 * 注册中心Registry返回服务...
- **容器(Container)**:用于加载、运行服务提供者和消费者。 3. **Dubbo配置** - 在服务提供者的`dubbo.properties`或XML配置文件中,需定义接口、实现类、版本、分组、注册中心等信息。 - 服务消费者也需要...
- **Container**:服务容器,负责服务的启动和运行。 2. **Dubbo服务器注册与发现的流程?** - **服务容器**启动并加载服务提供者。 - **服务提供者**向注册中心注册服务。 - **服务消费者**订阅所需服务。 -...
1. 服务容器Container负责启动,加载,运行服务提供者。 2. 服务提供者Provider在启动时,向注册中心注册自己提供的服务。 3. 服务消费者Consumer在启动时,向注册中心订阅自己所需的服务。 4. 注册中心Registry返回...
5. **容器(Container)**:用于运行服务提供者和消费者的应用容器,如Spring Container,它可以管理和启动Dubbo服务。 二、架构设计 Dubbo采用典型的三层架构设计: 1. **展示层(Presentation Layer)**:...
- **容器(Container)**:承载服务运行的环境。 3. **Dubbo支持哪些通信协议?** Dubbo支持多种通信协议,如Dubbo协议、RMI、Hessian、HTTP、Webservice等。其中,Dubbo协议基于TCP,具有较高的性能和低开销。 ...
例如,core模块提供了基础的RPC功能,provider模块负责服务提供者的实现,consumer模块关注服务消费者的逻辑,registry模块处理服务注册与发现,而container模块则用于容器化部署。 3. **服务注册与发现** dubbox-...
服务提供者通过启动服务容器(如Spring)加载服务实现类,并通过配置暴露服务到注册中心。 5. **服务消费者如何消费服务?** 服务消费者通过从注册中心获取服务提供者的信息,然后通过Dubbo的API或Spring的注解来...
9. **Container层**:容器层,承载服务,如Spring容器。 10. **Exchanger层**:交换器层,处理网络通信的细节。 **Dubbo和Spring Cloud的关系与区别?** 两者都是微服务治理框架,但Spring Cloud更全面,包含一系列...
7. **容器(Container)**:运行服务提供者和消费者的环境,如Spring、Spring Boot等,它们可以简化Dubbo的集成和管理。 接下来,我们来看看Duboo在实际使用中的关键特性: 1. **服务注册与发现**:服务提供者启动时...