我想知道在 JDBC 中验证isWrapperFor
和解包函数的正确方法。这里使用HIRAConnection
和标准Connection
类。
HIRAConnection hiraCon1 = (HIRAConnection) ds.getConnection();
Connection conn = ds.getConnection();
if (hiraCon1 instanceof Wrapper) {
// try to use java 6 unwrapping
try {
Wrapper w = conn;
if (hiraCon1.isWrapperFor(Connection.class)) {
hiraCon1 = conn.unwrap(HIRAConnection.class);
hiraCon1= hiraCon1.unwrap(HIRAConnection.class);
hiraCon1= ds.unwrap(HIRAConnection.class);//returns SQLException
}
if (hiraCon1.isWrapperFor(HIRAConnection.class)) {
hiraCon1 = conn.unwrap(HIRAConnection.class);
hiraCon1 = hiraCon1.unwrap(HIRAConnection.class);
}
if (conn.isWrapperFor(com.hira.HIRAConnection.class)) {
hiraCon1 = conn.unwrap(com.hira.HIRAConnection.class);
}
if (conn.isWrapperFor(Connection.class)) {
hiraCon1 = conn.unwrap(com.hira.HIRAConnection.class);
}
} catch (Throwable t) {
System.out.println("Failed to unwrap connection using java 6 facilities");
}
}
使用java.sql.Wrapper
的正确方法记录在其javadoc中。
对于isWrapperFor(Class<?> iface)
:
如果实现接口参数或 直接或间接地为这样做的对象的包装器。返回 否则为假。如果这实现了接口,则返回 true, 否则,如果这是一个包装器,则返回递归的结果 在包装的对象上调用
isWrapperFor
。如果这不行 实现接口并且不是包装器,返回 false。这 方法应作为低成本操作实施unwrap
,以便调用方可以使用此方法避免昂贵的unwrap
可能会失败的调用。如果此方法返回 true,则调用unwrap
用同样的论点应该成功。参数:
iface
- 定义接口的类。
返回:true,
如果这实现了接口或直接或间接包装了这样做的对象。
对于unwrap(Class<T> iface)
:
返回一个对象,该对象实现给定接口以允许访问 到非标准方法或代理未公开的标准方法。 如果接收器实现接口,则结果是 接收器或接收器的代理。如果接收器是包装器,并且 包装的对象实现接口,然后结果是 包装的对象或包装对象的代理。否则返回 在包装的对象或
unwrap
代理该结果。如果接收器不是包装器并且没有 实现接口,然后抛出一个SQLException
。类型参数:
T
- 由此类对象建模的类的类型
参数:iface
- 定义结果必须实现的接口的类。
返回:
实现接口的对象。可以是实际实现对象的代理。
抛出:SQLException
- 如果未找到实现接口的对象
换句话说,您可以首先使用wrapperFor
检查包装器是否可以解包到接口,然后您可以使用unwrap
真正解包到该接口。请注意,该规范仅提到对解包到接口的支持,因此实际上可能无法解包到具体类。
这是否有效取决于所使用的驱动程序(并非所有驱动程序都支持解包,或者它们可能没有任何有用的解包(,如果您使用的是连接池库,则完全可能不允许您解包到(例如(基础连接,因为这样做可能会允许您绕过或打破连接池的某些限制和要求。
因此,使用包装的正确方法是:
Connection conn = ds.getConnection();
if (conn.isWrapperFor(HiraConnection.class)) {
HIRAConnection hiraCon1 = conn.unwrap(HiraConnection.class);
// use hiraCon1...
)
但是,如果HiraConnection
是具体类而不是接口,则这可能不起作用。解包通常也会导致代码变脆。除非绝对必要,否则通常最好避免依赖特定于驱动程序的接口。
关于您问题中的代码的一些评论:
- 如果您知道
HIRAConnection hiraCon1 = (HIRAConnection) ds.getConnection();
有效,那么您根本不需要解开包装。 - 检查
hiraCon1 instanceof Wrapper
是一个无用的检查,因为如果HIRAConnection
实现了java.sql.Connection
,那么它将始终实现java.sql.Wrapper
(否则运行你的代码会产生ClassNotFoundException
java.sql.Wrapper
这意味着你在Java 5或更低版本上运行它(。 - 检查
hiraCon1.isWrapperFor(Connection.class)
然后将conn
解开包装以HIRAConnection
是不安全的,也没有意义。如果要解开包装conn
以HIRAConnection
,则需要使用conn.isWrapperFor(HiraConnection.class)
hiraCon1= ds.unwrap(HIRAConnection.class);
抛出SQLException
并不意外:javax.sql.DataSource
实现不太可能将自己视为连接的包装器。- 检查
hiraCon1.isWrapperFor(HIRAConnection.class)
有点奇怪:您已经知道hiraCon1
是一个HIRAConnection
- 如前所述,在检查
hiraCon1
后解开conn
是没有意义的。 - 检查
conn.isWrapperFor(Connection.class)
有点奇怪:您已经知道conn
是一个Connection
- 检查
conn.isWrapperFor(Connection.class)
然后使用conn.unwrap(com.hira.HIRAConnection.class)
是不安全的,因为您只检查了conn
是否解开包装以Connection
,而不是HIRAConnection
。