代理人
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;}@Overridepublic 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;}@Overridepublic Statement createStatement() throws SQLException {return target.createStatement();}@Overridepublic 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而不是直接方法调用:
- abort()
- getSchema()
- setSchema()
- getNetworkTimeout()
- setNetworkTimeout()
这些方法已添加到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);}@Overridepublic void setSchema(String schema) throws SQLException {getTarget().setSchema(schema);}@Overridepublic String getSchema() throws SQLException {return getTarget().getSchema();}@Overridepublic void abort(Executor executor) throws SQLException {getTarget().abort(executor);}@Overridepublic void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {getTarget().setNetworkTimeout(executor, milliseconds);}@Overridepublic 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使用连接装饰器作为默认的连接拦截机制。
实际的装饰器版本在运行时解析,并且加载机制由以下组件构成:
实际的连接装饰器工厂通过以下方法解决:
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