為vert x框架新增druid連線池支援

晦若晨曦發表於2017-12-14

vert.x

vert.x是一個優秀的,領先的,快速更新的非同步網路服務框架,可以支援tcp/udp/http等多種網路服務,功能強大,效能優越。

vert.x官網

vert.x框架支援多種語言,包括java,javascript,groovy,ruby等,在此處採用java語言。

vert.x從來不吝於支援最先進的技術,比如最新的vert.x已經充分支援了java8的各種特性。程式碼風格很接近node.js。簡潔有效。

非同步框架的通病在於回撥地獄,相比於node.js的promise等方案,vert.x也提供了類似的方案,更可以採用協程的方式一勞永逸的解決回撥地獄,同時享受更好的效能。

解析

vert.x預設採用的資料庫連線池是c3p0連線池。由阿里巴巴提供的druid連線池無疑是現在可用的最優秀的免費連線池之一,同時也是為了和其它專案保持同步,以及c3p0的一些坑。決定換用druid連線池。

可是vert.x並沒有提供druid連線池的支援,在官方的文件上對於連線池也是語焉不詳,於是一怒之下clone原始碼來看。

在vert-jdbc-client專案下,我不出意料的找到了這麼一句話:

String DEFAULT_PROVIDER_CLASS =  "io.vertx.ext.jdbc.spi.impl.C3P0DataSourceProvider";
複製程式碼

然後在實現類中找到了這麼一段:

String providerClass = config.getString("provider_class");
        if (providerClass == null) {
          providerClass = DEFAULT_PROVIDER_CLASS;
        }
複製程式碼

可見在這裡通過配置provider_class可以指定一個資料來源。那麼下一步就是仿照著C3P0DataSourceProvider來實現一個provider咯。

public interface DataSourceProvider {

  int maximumPoolSize(DataSource dataSource, JsonObject config) throws SQLException;

  DataSource getDataSource(JsonObject config) throws SQLException;

  void close(DataSource dataSource) throws SQLException;
}
複製程式碼

我們需要實現的就是這麼一個介面,其實關鍵的就在於getDataSource這麼一個方法。

實現

druid的資料來源入口是DruidDataSource。我們需要在getDataSource方法中根據引數配置一個資料來源並返回。

druid的配置引數還是很多的,一個個去判斷十分麻煩,這裡採用了一個偷懶的方法,用反射的方式去呼叫set方法來設定引數。

需要注意的是在反射呼叫中,Integer型別和int型別是不能通用的兩個型別,也就是說沒有自動裝箱一類的機制。所以需要對配置中涉及到的幾個基本變數做一下判斷和處理。否則會導致無法正確找到set方法並複製.

@Override
    public DataSource getDataSource(JsonObject config) throws SQLException {
        DruidDataSource ds = new DruidDataSource();
        Method[] methods = DruidDataSource.class.getMethods();
        Map<String,Method> methodmap = new HashMap<>();
        for (Method method : methods) {
            methodmap.put(method.getName(),method);
        }

        for (Map.Entry<String, Object> entry : config) {
            String name = entry.getKey();

            if ("provider_class".equals(name)) {
                continue;
            }

            String mName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);

            try {
                Class paramClazz = entry.getValue().getClass();
                if(paramClazz.equals(Integer.class)){
                    paramClazz = int.class;
                }else if(paramClazz.equals(Long.class)){
                    paramClazz = long.class;
                }else if(paramClazz.equals(Boolean.class)){
                    paramClazz = boolean.class;
                }
                Method method = DruidDataSource.class.getMethod(mName, paramClazz);
                method.invoke(ds, entry.getValue());
            } catch (NoSuchMethodException e) {
                logger.warn("no such method:" + mName);
                System.out.println(entry.getValue().getClass());
                );
            } catch (InvocationTargetException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return ds;
    }

複製程式碼

相關文章