工作一年,一直想写博客记录和分享一些想法,做一名分享的Coder,尽力去写一些高质量的博文。希望能够坚持下去,对博文有建议或意见的朋友们可以联系我。
个人邮箱:[email protected]
首先让我们回忆一下在编写JDBC代码的时候,我们在获取Connection的时候怎么获取的
Class.forName("com.mysql.jdbc.Driver");
Connection connection= DriverManager.getConnection("jdbc:mysql:///mydatabase", "root", "root");
第一步我们通常叫注册驱动,那什么叫做注册驱动?都是通过什么实现的注册驱动呢?下面让我们带着问题去了解服务提供框架。
多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。——–《Effective Java》
sun公司在制定JDBC这套规则的时候,如果MySQL还没有出现,sun公司会再给MySQL重新制定一套规则吗?一定不会吧,可是这个问题怎么解决?
1.所以sun公司首先自己定义了一套服务接口,就是这些这些主要步骤的定义。
2.MySQL服务商去实现这套接口。
3.现在调用者想使用MySQL提供的服务,首先进行注册,也就是调用提供者者注册API,将MySQL的实现的服务提供者接口添加到JDBC的注册列表中。
4.注册之后调用者只需要调用 服务访问API,告之我要使用哪一个SQL服务商的实现类,服务访问API就会调用服务提供者接口的实现返回对应的服务实例。
这里要说明一点因为服务的实现都是后于JDBC规则出现的,所以想实例化这些对象只能通过反射进行实例化,按照类名进行注册,所以服务提供者接口 的实现负责创建其服务实现的实例。同时使用服务提供者接口进行注册,对于MySQL而言就是Driver。
com.mysql.jdbc.Driver.java
package com.mysql.jdbc;
import com.mysql.jdbc.NonRegisteringDriver;
import java.sql.DriverManager;
import java.sql.SQLException;
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!");
}
}
}
java.sql.DriverManager.java
// List of registered JDBC drivers
private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList();
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver));
} else {
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
java.sql.Driver就是服务提供者接口,NonRegisteringDriver就是其实现类,com.mysql.jdbc.Driver只是进行注册。在静态代码块中调用了DriverManager.registerDriver方法,并且将实现类添加到JDBC的注册列表(registeredDrivers)。所以在我们通过反射加载com.mysql.jdbc.Driver就可以完成注册了。这也就是文章开头问题的答案。
1.首先通过getConnection获取
DriverManager.getConnection("jdbc:mysql:///mydatabase", "root", "root");
2.
java.sql.DriverManager.java
public static Connection getConnection(String url)
throws SQLException {
java.util.Properties info = new java.util.Properties();
// Gets the classloader of the code that called this method, may
// be null.
ClassLoader callerCL = DriverManager.getCallerClassLoader();
return (getConnection(url, info, callerCL));
}
3.
java.sql.DriverManager.java( 这是getConnection方法中的片段)
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
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;
}
}
}
重点是遍历registeredDrivers 这就上面注册服务的注册列表
aDriver.driver.connect(url, info);
这个就是服务提供者进行自己实现的方法,如果URL符合提供者自己的规则就返回对应Connection
(MySQL是通过字符串前缀进行匹配的,有兴趣的朋友可以自行查看源码)
所以对于JDBC来说Connection就是服务接口,DriverManager.registerDriver是提供者注册API,DriverManager.getConnection是服务访问API,Driver是服务提供者接口。
其实服务提供者框架作用主要是就是隐藏子类实现,而且可以不断的进行扩展,同时将这些服务整合到一起,使调用者察觉不到子类的不同。