代理人
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使用连接装饰器作为默认的连接拦截机制。
实际的装饰器版本在运行时解析,并且加载机制由以下组件构成:
实际的连接装饰器工厂通过以下方法解决:
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连接装饰器)进行选择。
结论
装饰器比代理器承担更多的配置开销,但是如果您想减少最后的性能下降,则值得考虑直接方法调用的优势。