当前位置:   article > 正文

dubbo启动服务之容器(Container)_dubbo monitor container

dubbo monitor container

from http://www.ccblog.cn/75.htm

讲解dubbo启动服务的时候先来了解下java的spi机制

一:SPI 简介

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。 目前有不少框架用它来做服务的扩展发现, 简单来说,它就是一种动态替换发现的机制, 举个例子来说, 有个接口,想运行时动态的给它添加实现,你只需要添加一个实现,而后,把新加的实现,描述给JDK知道就行啦(通过改一个文本文件即可) ,公司内部目前Dubbo框架就基于SPI机制提供扩展功能。

代码例子


  1. public interface Cmand {
  2.     public void execute();
  3. }
  4. public class ShutdownCommand implements Cmand {
  5.     public void execute() {
  6.         System.out.println("shutdown....");  
  7.     }
  8. }
  9. public class StartCommand implements Cmand {
  10.     public void execute() {
  11.         System.out.println("start....");
  12.     }
  13. }
  14. public class SPIMain {
  15.     public static void main(String[] args) {
  16.         ServiceLoader<Cmand> loader = ServiceLoader.load(Cmand.class);
  17.         System.out.println(loader);
  18.         
  19.         
  20.         for (Cmand Cmand : loader) {
  21.             Cmand.execute();
  22.         }
  23.     }
  24. }

配置:

com.unei.serviceloader.impl.ShutdownCommand  

com.unei.serviceloader.impl.StartCommand

运行结果:

  1. java.util.ServiceLoader[com.unei.serviceloader.Cmand]
  2. shutdown....
  3. start....

相关原理解答

1.配置文件为什么要放在META-INF/services下面?

ServiceLoader类定义如下:

private static final String PREFIX = "META-INF/services/"; (JDK已经写死了)

但是如果ServiceLoader在load时提供Classloader,则可以从其他的目录读取。

2.ServiceLoader读取实现类是什么时候实例化的? 

  1. public void reload() {
  2.         providers.clear();
  3.         lookupIterator = new LazyIterator(service, loader);
  4.     }
  5.     private ServiceLoader(Class<S> svc, ClassLoader cl) {
  6.         service = Objects.requireNonNull(svc, "Service interface cannot be null");
  7.         loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
  8.         acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
  9.         reload();
  10.     }


二: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方法里面):

  1. if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) {
  2.             Runtime.getRuntime().addShutdownHook(new Thread() {
  3.                 public void run() {
  4.                     for (Container container : containers) {
  5.                         try {
  6.                             container.stop();
  7.                             logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!");
  8.                         } catch (Throwable t) {
  9.                             logger.error(t.getMessage(), t);
  10.                         }
  11.                         synchronized (Main.class) {
  12.                             running = false;
  13.                             Main.class.notify();
  14.                         }
  15.                     }
  16.                 }
  17.             });
  18.             }

  原理:

服务提供方

停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。

然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。


服务消费方

停止时,不再发起新的调用请求,所有新的调用在客户端即报错。

然后,检测有没有请求的响应还没有返回,等待响应返回,除非超时,则强制关闭。

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

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/231643
推荐阅读
相关标签
  

闽ICP备14008679号