vlambda博客
学习文章列表

利用Dubbo的SPI扩展容器

在实际开发中,很多Dubbo的服务提供者都会运行在web容器上,如果提供者服务上同时对外提供http服务的话,这么做是有必要的,但如果你的服务提供者只是对外提供dubbo服务的话,那么用web容器就有些重了,因为毕竟web容器主要是用来响应http请求以及静态页面的。如果单独作为dubbo服务提供者,只需要通过一个main方法加载一个简单的spring容器将服务暴露出去即可。
注:本文以dubbo的2.6.5版本为例
  • 一、Dubbo的内置容器

dubbo内置了三种容器
Log4jContainer:只是针对log4j配置文件做了处理。

利用Dubbo的SPI扩展容器

LogbackContainer:只是针对logback日志配置文件做了处理。

利用Dubbo的SPI扩展容器

SpringContainer:
它的start方法会创建ClassPathXmlApplicationContext容器,然后分别执行refresh方法和start方法刷,暴露dubbo服务;其stop方法会执行ClassPathXmlApplicationContext的stop及close方法。

利用Dubbo的SPI扩展容器

可以看到,这三种容器,只有SpringContainer真正的加载了容器并暴露了服务,所以要用dubbo自带的容器的话,SpringContainer是必选的,可以单独使用,另外两个需要配合SpringContainer使用,但是如果要使用SpringContainer的话,你需要把配置文件放到指定的为止,因为源码中已经定义死了:

利用Dubbo的SPI扩展容器

所以我们用的时候一般是通过实现Container接口来自定义一个容器,然后重写Main类通过Dubbo的SPI机制加载自定义的容器,这样可以自定义加载配置文件。
  • 二、自定义Container

  • 2.1、首先用idea新建一个基于maven的java项目,添加dubbo,zk等依赖,具体的项目创建过程略过。

  • 2.2、写一个接口和实现类,用来对外暴露

利用Dubbo的SPI扩展容器

  • 2.3、添加spring配置文件,dubbo配置文件等

利用Dubbo的SPI扩展容器

  • 2.4、定义一个容器类,实现Container接口

package com.ayo;
import com.alibaba.dubbo.container.Container;import com.ayo.util.PathUtil;import org.springframework.context.support.FileSystemXmlApplicationContext;
/** * 自定义一个容器 */public class CustomContainer implements Container{
/** * spring容器上下文 */ static FileSystemXmlApplicationContext context;
/** * 启动容器 */ public void start() { try { String path = PathUtil.getAppConfPath().concat(PathUtil.sp()).concat("spring.xml"); context = new FileSystemXmlApplicationContext(path); }catch (Exception e){ e.printStackTrace(); } }
/** * 停止容器 */ public void stop() { try { if (context != null){ context.stop(); context.close(); context = null; } }catch (Exception e){ e.printStackTrace(); } }}
  • 2.5、在resources下建一个文件夹命名为META-INF,然后在META-INF下再建一个文件夹命名为dubbo,然后建立一个文件命名为com.alibaba.dubbo.container.Container,里面写上内容

利用Dubbo的SPI扩展容器

为什么要这么做?这就是Dubbo的SPI,不知道的可以看下,传送门:

  • 2.6、写一个Main类用于加载和启动自定义的Container

package com.ayo;
import com.alibaba.dubbo.common.extension.ExtensionLoader;import com.alibaba.dubbo.container.Container;import java.text.SimpleDateFormat;import java.util.Date;

/** * 自定义dubbo容器 * * @author ayo */public class Main {
/** * dubbo优雅关机 */ public static final String SHUTDOWN_HOOK_KEY = "dubbo.shutdown.hook";
private static volatile boolean running = true;
public static void main(String[] args) { try { final Container customContainer = ExtensionLoader.getExtensionLoader(Container.class).getExtension("custom"); //在dubbo优雅关机的时候会触发此钩子函数 if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { try { customContainer.stop(); System.out.println("Dubbo " + customContainer.getClass().getSimpleName() + " stopped!"); } catch (Throwable t) { t.printStackTrace(); } synchronized (Main.class) { running = false; Main.class.notify(); } } }); } customContainer.start(); System.out.println("Dubbo " + customContainer.getClass().getSimpleName() + " started!"); System.out.println(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " Dubbo service server started!"); } catch (RuntimeException e) { e.printStackTrace(); System.exit(1); } synchronized (Main.class) { while (running) { try { Main.class.wait(); } catch (Throwable e) { } } } }}
  • 2.7、运行Main类中的main方法

利用Dubbo的SPI扩展容器

  • 2.8、看下服务有没有注册到zk

  • 2.9、写个dubbo消费者测试下接口是否正常

package com.ayo;
import com.alibaba.dubbo.config.ApplicationConfig;import com.alibaba.dubbo.config.ReferenceConfig;import com.alibaba.dubbo.config.RegistryConfig;import com.ayo.service.UserService;
public class Consumer {
public static void main(String[] args) { //1.创建服务引用对象实例 ReferenceConfig<UserService> referenceConfig = new ReferenceConfig<UserService>();
//2.设置应用程序信息 ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-consumer"); referenceConfig.setApplication(applicationConfig);
//3.设置服务注册中心 RegistryConfig registryConfig = new RegistryConfig("zookeeper://192.168.209.129:2181"); referenceConfig.setRegistry(registryConfig);
//3.设置服务接口和超时时间 referenceConfig.setInterface(UserService.class); referenceConfig.setTimeout(5000);
//5.引用服务 UserService userService = referenceConfig.get();
//6.调用服务 System.out.println(userService.getUserName()); }}

需要demo的私我。