FlexyPool如何同时支持连接代理和装饰器

代理人

FlexyPool监视连接池使用情况,因此需要拦截连接关闭方法调用。
为了简单起见,第一个版本为此目的依赖动态代理:

private static class ConnectionInvocationHandler 
    implements InvocationHandler {

    public static final String CLOSE_METHOD_NAME = "close";

    private final Connection target;
    private final ConnectionCallback callback;

    public ConnectionInvocationHandler(
        Connection target, 
        ConnectionCallback callback) {
        this.target = target;
        this.callback = callback;
    }

    @Override
    public Object invoke(
        Object proxy, 
        Method method, 
        Object[] args) throws Throwable {
        if (CLOSE_METHOD_NAME.equals(method.getName())) {
            callback.close();
        }
        return method.invoke(target, args);
    }
}

代理调用的速度可能比装饰器慢,装饰器使用直接调用来调用目标方法。

由于所有连接池仍然使用代理,因此添加另一个代理层只会增加更多的呼叫时间开销,因此现在FlexyPool也支持连接装饰器。

装饰工

ConnectionDecorator包装基础数据库连接,将所有调用委派给实际的对象实例。 就像它的代理服务器代理一样,只有close方法可以执行任何额外的逻辑:

public class ConnectionDecorator 
    implements Connection {

    private final Connection target;

    private final ConnectionCallback callback;

    public ConnectionDecorator(
        Connection target, 
        ConnectionCallback callback) {
        this.target = target;
        this.callback = callback;
    }

    public Connection getTarget() {
        return target;
    }

    public ConnectionCallback getCallback() {
        return callback;
    }

    @Override
    public Statement createStatement() 
        throws SQLException {
        return target.createStatement();
    }
    
    @Override
    public void close() 
        throws SQLException {
        callback.close();
        target.close();
    }
    
    /**
     *  More methods omitted for brevity sake
     */

    public void setSchema(String schema) 
        throws SQLException {
        ReflectionUtils.invoke(
            target,
            ReflectionUtils.getMethod(
                target, 
                "setSchema", 
                String.class
            ),
            schema
        );
    }

    public String getSchema() 
        throws SQLException {
        return ReflectionUtils.invoke(
            target,
            ReflectionUtils.getMethod(
                target, 
                "getSchema"
            )
        );
    }

    public void abort(Executor executor) 
        throws SQLException {
        ReflectionUtils.invoke(
            target,
            ReflectionUtils.getMethod(
                target, 
                "abort", 
                Executor.class
            ),
            executor
        );
    }

    public void setNetworkTimeout(
        Executor executor, 
        int milliseconds) 
        throws SQLException {
        ReflectionUtils.invoke(
            target,
            ReflectionUtils.getMethod(
                target, 
                "setNetworkTimeout", 
                Executor.class, 
                int.class
            ),
            executor, 
            milliseconds
        );
    }

    public int getNetworkTimeout() 
        throws SQLException {
        return (Integer) 
            ReflectionUtils.invoke(
                target,
                ReflectionUtils.getMethod(
                    target, 
                    "getNetworkTimeout"
                )
            );
    }
}

您可能已经注意到,某些方法使用Java Reflection而不是直接方法调用:

这些方法已添加到Java 1.7中,使用Java 1.6编译项目时,直接调用将失败。 因为Java 1.6是大多数FlexyPool模块的最低要求,所以这些方法通过Java反射调用转发传入的方法调用。 省略这些方法不是可选的,因为在1.7 JVM上, Connection装饰器将没有这些方法,并且将引发类装入错误。

在至少使用Java 1.7的项目中,FlexyPool还提供了Java7ConnectionDecorator

public class Java7ConnectionDecorator 
    extends ConnectionDecorator {

    public Java7ConnectionDecorator(
        Connection target, 
        ConnectionCallback callback) {
        super(target, callback);
    }

    @Override
    public void setSchema(String schema) 
        throws SQLException {
        getTarget().setSchema(schema);
    }

    @Override
    public String getSchema() 
        throws SQLException {
        return getTarget().getSchema();
    }

    @Override
    public void abort(Executor executor) 
        throws SQLException {
        getTarget().abort(executor);
    }

    @Override
    public void setNetworkTimeout(
        Executor executor, 
        int milliseconds) 
        throws SQLException {
        getTarget().setNetworkTimeout(executor, milliseconds);
    }

    @Override
    public int getNetworkTimeout() 
        throws SQLException {
        return getTarget().getNetworkTimeout();
    }
}

此类不是核心库的一部分,包含在单独的Java 1.7兼容模块中。 要使用它,您需要添加以下Maven依赖项:

<dependency>
    <groupId>com.vladmihalcea.flexy-pool</groupId>
    <artifactId>flexy-pool-core-java7</artifactId>
    <version>${flexy-pool.version}</version>
</dependency>

服务发现机制

从一开始,FlexyPool就为配置ConnectionProxyFactory实例提供了支持,因此切换到装饰器不需要任何繁琐的代码重构。

1.2.4发行版之前,默认的连接提供程序是JdkConnectionProxyFactory ,它使用动态代理。
从1.2.4开始,FlexyPool使用连接装饰器作为默认的连接拦截机制。

实际的装饰器版本在运行时解析,并且加载机制由以下组件构成:

flexypoolconnectionproxydecorator

实际的连接装饰器工厂通过以下方法解决:

public ConnectionDecoratorFactory resolve() {
    int loadingIndex = Integer.MIN_VALUE;
    ConnectionDecoratorFactory connectionDecoratorFactory = null;
    Iterator<ConnectionDecoratorFactoryService> 
        connectionDecoratorFactoryServiceIterator = serviceLoader.iterator();
    while (connectionDecoratorFactoryServiceIterator.hasNext()) {
        try {
            ConnectionDecoratorFactoryService connectionDecoratorFactoryService = 
                connectionDecoratorFactoryServiceIterator.next();
            int currentLoadingIndex = connectionDecoratorFactoryService.loadingIndex();
            if (currentLoadingIndex > loadingIndex) {
                ConnectionDecoratorFactory currentConnectionDecoratorFactory = 
                    connectionDecoratorFactoryService.load();
                if (currentConnectionDecoratorFactory != null) {
                    connectionDecoratorFactory = currentConnectionDecoratorFactory;
                    loadingIndex = currentLoadingIndex;
                }
            }
        } catch (LinkageError e) {
            LOGGER.info("Couldn't load ConnectionDecoratorFactoryService on the current JVM", e);
        }
    }
    if (connectionDecoratorFactory != null) {
        return connectionDecoratorFactory;
    }
    throw new IllegalStateException("No ConnectionDecoratorFactory could be loaded!");
}

就像MetricsFactory一样 ,每个连接装饰器工厂都有一个关联的服务提供者 。 可以在运行时加载多个此类服务提供程序(默认的Java 1.6连接修饰器服务或Java 1.7之一)。 根据索引(最新的Java版本优先)和当前的JVM JDBC版本支持(在Java 1.6运行时环境中无法解析Java 1.7连接装饰器)进行选择。

结论

装饰器比代理器承担更多的配置开销,但是如果您想减少最后的性能下降,则值得考虑直接方法调用的优势。

翻译自: https://www.javacodegeeks.com/2015/08/how-does-flexypool-support-both-connection-proxies-and-decorators.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值