您的位置:首页 > 其它

Class.forName()做了什么?

2016-03-13 20:01 411 查看
JDBC连接一般需要以下步骤:

1 加载驱动

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


2 获取连接对象

Connection con=
DriverManager.getConnection("jdbc:mysql://localhost:3306/homeworksubmit?user=root&password=root&useUnicode=true&characterEncoding=UTF-8");


3 创建命令对象

Statement stmt =
con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);


4 执行sql语句

Result rs=stmt.executeQuery(sql);


但是有疑问的是第一步,没有返回对像,追踪到源码:

Returns the {@code Class} object associated with the class or
interface with the given string name.
equivalent to:
{@code Class.forName(className, true, currentLoader)}


后面几步获取的对象一般都是方便下一步的调用,所以Class.forName()到底如何执行的,以及做了哪些工作,知悉了这些,才能对JDBC连接的理解更加透彻。

在这里首先贴出Driver类源码:

* The Java SQL framework allows for multiple database drivers. Each driver
* should supply a class that implements the Driver interface
*
* <p>
* The DriverManager will try to load as many drivers as it can find and then
* for any given connection request, it will ask each driver in turn to try to
* connect to the target URL.
*
* <p>
* It is strongly recommended that each Driver class should be small and
* standalone so that the Driver class can be loaded and queried without
* bringing in vast quantities of supporting code.
*
* <p>
* When a Driver class is loaded, it should create an instance of itself and
* register it with the DriverManager. This means that a user can load and
* register a driver by doing Class.forName("foo.bah.Driver")


从中可以获取以下信息:

每个驱动类都必须实现Driver接口

当驱动被加载的时候,它首先实例化对象,并将其注册到DriverManager。

com.mysql.jdbc.Driver中的部分代码:

在初始化Driver类的时候,其中的静态代码也会执行,于是乎自动执行下面的语句:

java.sql.DriverManager.registerDriver(new Driver());


public class Driver extends NonRegisteringDriver implements java.sql.Driver {
// ~ Static fields/initializers
// ---------------------------------------------

//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}

……
}


就这样,使用forName()初始化Driver后,MySql驱动就自动向DriverManagemer类注册了,使得我们能通过DriverManager获得对MysqL的连接。

贴出registerDriver()源码解释:

* Registers the given driver with the <code>DriverManager</code>.


部分实现代码:

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

/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}

println("registerDriver: " + driver);

}


new DriverInfo(driver),接下来在看一下DriverInfo(driver)类:

DriverInfo非常简单,用于保存Driver的信息,只有3个成员变量,Driver,DriverClass和 DriverClassName,意义非常明显。

在一个类加载入内存的时候,类中的静态初始化过程会执行,这样就完成了驱动程序的注册过程。然后重点看一下建立数据库连接的代码,在getConnection函数中,

/**
* Attempts to establish a connection to the given database URL.
* The <code>DriverManager</code> attempts to select an appropriate driver from
* the set of registered JDBC drivers.
*
* @param url a database url of the form
*  <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
* @return a connection to the URL
* @exception SQLException if a database access error occurs
*/


实现函数:

@CallerSensitive
public static Connection getConnection(String url)
throws SQLException {

java.util.Properties info = new java.util.Properties();
return (getConnection(url, info, Reflection.getCallerClass()));
}


到这里基本完成连接了。接下来,考虑一下,源码中说尝试一个合适的驱动从注册的JDBC驱动中,轮询方式,当注册的驱动多了,连接速度会越慢。JDBC连接数据库的速度很慢, 是不是和这种实现方式有关联呢?看一下Driver类:

public class Driver extends NonRegisteringDriver implements java.sql.Driver


看一下NonRegisteringDriver的实现:

public java.sql.Connection connect(String url, Properties info)
throws SQLException {
if (url != null) {
if (StringUtils.startsWithIgnoreCase(url, LOADBALANCE_URL_PREFIX)) {
return connectLoadBalanced(url, info);
} else if (StringUtils.startsWithIgnoreCase(url,
REPLICATION_URL_PREFIX)) {
return connectReplicationConnection(url, info);
}
}

Properties props = null;

if ((props = parseURL(url, info)) == null) {
return null;
}

try {
Connection newConn = new com.mysql.jdbc.Connection(host(props),
port(props), props, database(props), url);

return newConn;
} catch (SQLException sqlEx) {
// Don't wrap SQLExceptions, throw
// them un-changed.
throw sqlEx;
} catch (Exception ex) {
throw SQLError.createSQLException(Messages
.getString("NonRegisteringDriver.17") //$NON-NLS-1$
+ ex.toString()
+ Messages.getString("NonRegisteringDriver.18"), //$NON-NLS-1$
SQLError.SQL_STATE_UNABLE_TO_CONNECT_TO_DATASOURCE);
}
}


先parseURL,然后使用Connection去建立连接。parseURL只是简单的字符串分析,主要是分析传入的连接字符串是否满足 “jdbc:mysql://host:port/database“的格式,如果不满足,直接返回null,然后由DriverManager去试验下 一个Driver。如果满足,则建立一个Connection对象建立实际的数据库连接,由此可见刚刚的问题答案是:DriverManager的轮询查询注册的Driver对象的工作方式所带来的性能代价并不是很大,主工作量只是parseURL函数。

源码追溯到这里结束了,剩下的就不去管了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: