jdbc桥接mysql_桥接模式在JDBC源码中的应用

在 JDBC API 中,大家非常熟悉的 Driver 类就是桥接对象。使用 JDBC 时通过 Class.forName() 方法可以动态加载各个数据库厂商实现的 Driver 类。

下面以 MySQL 的实现为例,具体客户端应用代码如下:

// 1. 注册JDBC驱动

// 反射机制加载驱动类

Class.forName("com.mysql.jdbc.Driver");

// 2. 获取连接Connection

conn = DriverManager.getConnection(DB_URL,USER,PASS);

// 3. 获取sql语句的对象Statement

Statement stmt = conn.createStatement();

// 4. 执行sql语句,并返回结果

ResultSet rs = stmt.executeQuery(sql);

以下为 Driver 接口的定义。

public interface Driver {

Connection connect(String url, java.util.Properties info) throws SQLException;

boolean acceptsURL(String url) throws SQLException;

DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info) throws SQLException;

int getMajorVersion();

int getMinorVersion();

boolean jdbcCompliant();

public Logger getParentLogger() throws SQLFeatureNotSupportedException;

}

Driver 在 JDBC 中并没有具体实现,具体的功能实现由各厂商完成,下面是 MySQL 中 Driver 的具体实现。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {

public Driver() throws SQLException {

}

static {

try {

DriverManager.registerDriver(new Driver());

} catch (SQLException var1) {

throw new RuntimeException("Can't register driver!");

}

}

}

Driver 实现类的代码特别简短,其中只调用了 DriverManager 中的 registerDriver 方法来注册驱动。当驱动注册完成后,就会开始调用 DriverManager 中的 getConnection 方法了。

当我们执行到 Class.forName("com.mysql.jdbc.Driver") 方法的时候,就会执行 com.mysql.jdbc.Driver 类的静态块中的代码。静态块中的代码只是调用了一下 DriverManager 的 registerDriver() 方法,然后将 Driver 对象注册到 DriverManager 中。下面继续跟进 DriverManager 类,相关代码如下。

public class DriverManager {

// List of registered JDBC drivers

private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList();

private static volatile int loginTimeout = 0;

......

private final static Object logSync = new Object();

private DriverManager(){}

static {

loadInitialDrivers();

println("JDBC DriverManager initialized");

}

......

public static synchronized void registerDriver(java.sql.Driver driver)

throws SQLException {

if(driver != null) {

registeredDrivers.addIfAbsent(new DriverInfo(driver));

} else {

// This is for compatibility with the original DriverManager

throw new NullPointerException();

}

println("registerDriver: " + driver);

}

......

}

在注册之前,将传过来的 Driver 对象封装成一个 DriverInfo 对象。

class DriverInfo {

final Driver driver;

DriverInfo(Driver driver) {

this.driver = driver;

}

public boolean equals(Object other) {

return (other instanceof DriverInfo)

&& this.driver == ((DriverInfo) other).driver;

}

public int hashCode() {

return driver.hashCode();

}

public String toString() {

return ("driver[className=" + driver + "]");

}

}

DriverInfo 本身其实就是 Driver。接下来继续执行客户端代码的第二步,调用 DriverManager 的 getConnection() 方法获取连接对象,下面跟进源码。

public class DriverManager{

......

public static Connection getConnection(String url,

java.util.Properties info) throws SQLException {

return (getConnection(url, info, Reflection.getCallerClass()));

}

public static Connection getConnection(String url,

String user, String password) throws SQLException {

java.util.Properties info = new java.util.Properties();

if (user != null) {

info.put("user", user);

}

if (password != null) {

info.put("password", password);

}

return (getConnection(url, info, Reflection.getCallerClass()));

}

public static Connection getConnection(String url)

throws SQLException {

java.util.Properties info = new java.util.Properties();

return (getConnection(url, info, Reflection.getCallerClass()));

}

private static Connection getConnection(

String url, java.util.Properties info, Class> caller) throws SQLException {

ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;

synchronized (DriverManager.class) {

// synchronize loading of the correct classloader.

if (callerCL == null) {

callerCL = Thread.currentThread().getContextClassLoader();

}

}

if(url == null) {

throw new SQLException("The url cannot be null", "08001");

}

println("DriverManager.getConnection(\"" + url + "\")");

SQLException reason = null;

for(DriverInfo aDriver : registeredDrivers) {

if(isDriverAllowed(aDriver.driver, callerCL)) {

try {

println(" trying " + aDriver.driver.getClass().getName());

Connection con = aDriver.driver.connect(url, info);

if (con != null) {

// Success!

println("getConnection returning " + aDriver.driver.getClass().getName());

return (con);

}

} catch (SQLException ex) {

if (reason == null) {

reason = ex;

}

}

} else {

println(" skipping: " + aDriver.getClass().getName());

}

}

if (reason != null) {

println("getConnection failed: " + reason);

throw reason;

}

println("getConnection: no suitable driver found for "+ url);

throw new SQLException("No suitable driver found for "+ url, "08001");

}

}

在 getConnection() 中,又会调用各自厂商实现的 Driver 的 connect() 方法获得连接对象。这样就巧妙地避开了使用继承,为不同的数据库提供了相同的接口。JDBC API 中的 DriverManager 就是桥,如下图所示。

437014f002b770c9ed40124a98e2d2f7.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值