Presto Connector开发


Presto可以支持很多的数据源,并且数据源都是以plugin的方式添加的。Presto可以很方便地添加新的Connector,接下来以自带的presto-example-http为例,详细介绍在Presto中如何添加一个新的Connector。

一、创建Maven工程

在Presto目录下创建一个presto-example-http的目录,在presto-example-http根目录下编辑pom.xml配置文件,以下几项是必须配置的。

  • 将当前工程加入到Presto组中,版本需要和整个Presto工程的版本一致。

      <parent>
      	<groupId>com.facebook.presto</groupId>
      	<artifactId>presto-root</artifactId>
      	<version>${project.version}</version>
      </parent>
    
  • 描述当前工程的信息,packaging选项为presto-plugin,在打包编译时,会将当前工程打包编译到Presto的plugin目录下。

      <artifactId>presto-example-http</artifactId>
      <description>Presto - Example HTTP Connector</description>
      <packaging>presto-plugin</packaging>
    
  • 每个Plugin工程都需要依赖presto-spi模块,presto-spi中统一定义了各种API接口。

      <!-- Presto SPI -->
      <dependency>
          <groupId>com.facebook.presto</groupId>
          <artifactId>presto-spi</artifactId>
          <scope>provided</scope>
      </dependency>
    

presto-spi最终会打包编译到presto/lib目录下,所有的plugin模块都会加载lib下的jar,所以当前的presto-spi不需要重复打包编译到当前的plugin目录中。

在整个Presto工程编译时,需要将我们自定义添加的connector也编译打包到plugin目录下,通过以下的配置即可达到我们的目的。

  • 在Presto根目录下的pom.xml中,将我们新增的Connector加入到modules中:

      <modules>
          <module>presto-example-http</module>
      </modules>
    
  • 在presto-server的src/main/assembly/presto.xml配置文件中,注册新增的Connector:

      <fileSets>
          <!-- plugins -->
          <fileSet>
              <directory>${project.build.directory}/dependency/presto-example-http-${project.version}</directory>
              <outputDirectory>plugin/example-http</outputDirectory>
          </fileSet>
      </fileSets>
    

经过以上步骤,新增Connector的准备工作就已经完成。在开发过程中根据具体实现使用到的类来添加其依赖。Plugin使用了独立的类加载器,和其他的类是隔离的,因此Plugin可以使用不同版本的类库,区别于Presto内部使用的版本,例如当前Plugin要使用的jar包与Presto内部所使用的版本有冲突,那么Plugin内部可以定义声明不同于Presto内部所使用的jar包版本。

二、注册Plugin

每个Plugin必须要实现com.facebook.presto.spi.Plugin接口,Presto会在服务启动环节加载所有的Plugin,入口代码在com.facebook.presto.server.PrestoServer.run方法中:

// PrestoServer.scala
public void run()
{
	Bootstrap app = new Bootstrap(modules.build());
	Injector injector = app.initialize();
	injector.getInstance(PluginManager.class).loadPlugins();
}

injector为Guice的注解加载工具,其含义为:实例化PluginManager并且调用其loadPlugins方法。loadPlugins方法的逻辑为:读取Presto部署的Plugin目录,构造类加载器,最终调用PluginManager.installPlugin(Plugin plugin)方法向PrestoServer注册Plugin。

// PluginManager.java
public void loadPlugins()
        throws Exception
{
    for (File file : listFiles(installedPluginsDir)) {
        if (file.isDirectory()) {
            loadPlugin(file.getAbsolutePath());
        }
    }
}

private void loadPlugin(String plugin)
        throws Exception
{
    URLClassLoader pluginClassLoader = buildClassLoader(plugin); // 默认使用PluginClassLoader.java类加载器
    try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(pluginClassLoader)) {
        loadPlugin(pluginClassLoader);
    }
}

private void loadPlugin(URLClassLoader pluginClassLoader)
{
    ServiceLoader<Plugin> serviceLoader = ServiceLoader.load(Plugin.class, pluginClassLoader);
    List<Plugin> plugins = ImmutableList.copyOf(serviceLoader);

    for (Plugin plugin : plugins) {
        installPlugin(plugin);
    }
}

public void installPlugin(Plugin plugin)
{
    for (ConnectorFactory connectorFactory : plugin.getConnectorFactories()) {
        if (disabledConnectors.contains(connectorFactory.getName())) {
            log.info("Skipping disabled connector %s", connectorFactory.getName());
            continue;
        }
        log.info("Registering connector %s", connectorFactory.getName());
        connectorManager.addConnectorFactory(connectorFactory);
    }
}

从上面我们可以看到,最终需要调用Plugin的getConnectorFactories方法注册connector,getConnectorFactories会返回一个ConnectorFactory列表,并且将该ConnectorFactory加入到ConnectorManager中,那么在注册一个Connector时需要overwrite getConnectorFactories方法,在presto-example-http module的ExamplePlugin类中进行了实现:

// ExamplePlugin.java
@Override
public Iterable<ConnectorFactory> getConnectorFactories()
{
    return ImmutableList.of(new ExampleConnectorFactory());
}

这样整个Plugin的注册工作就完成了。工厂类ExampleConnectorFactory继承自接口com.facebook.presto.spi.ConnectorFactory(该接口属于presto-spi工程),因此ExampleConnectorFactory类需要实现以下三个方法:

  • getName:返回Plugin的名称。
  • getHandleResolver:返回handler解析器,该Connector各种相应处理类ConnectorHandleResolver。
  • create(String connectorId, Map<String, String> config):注册该Plugin所要启动的module,设置Connector的相关配置参数并完成Connector的实例化。

三、定义Connector

在注册Plugin时会将ConnectorFactory注册到ConnectorManager,而且最终是需要通过ConnectorFactory.create方法来实例化Connector,这个过程的实现是在PrestoServer.run方法中加载catalog配置:

injector.getInstance(StaticCatalogStore.class).loadCatalogs();

使用StaticCatalogStore加载Presto中配置的各个Catalog,loadCatalogs读取到Catal

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值