工作一年,一直想写博客记录和分享一些想法,做一名分享的Coder,尽力去写一些高质量的博文。希望能够坚持下去,对博文有建议或意见的朋友们可以联系我。
个人邮箱:zhangshaoqiangchn@gmail.com前言: 首先让我们回忆一下在编写JDBC代码的时候,我们在获取Connection的时候怎么获取的
Class.forName("com.mysql.jdbc.Driver");
Connection connection= DriverManager.getConnection("jdbc:mysql:///mydatabase", "root", "root");
- 通过反射的方式将com.mysql.jdbc.Driver的class文件通过类加载器加载到内存中
- 通过DriverManager得到Connection
定义:
多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。——–《Effective Java》组件:
- 服务接口(Service Interface):提供者去实现的。
- 提供者者注册API(provider Registration API):系统用来注册实现的。
- 服务访问API(Service Access API):客户端用来获取实例的。
- 服务提供者API(Service Provider Interface)(可选):创建其服务实例对象的。
步骤:
1.所以sun公司首先自己定义了一套服务接口,就是这些这些主要步骤的定义。
2.MySQL服务商去实现这套接口。
3.现在调用者想使用MySQL提供的服务,首先进行注册,也就是调用提供者者注册API,将MySQL的实现的服务提供者接口添加到JDBC的注册列表中。
4.注册之后调用者只需要调用 服务访问API,告之我要使用哪一个SQL服务商的实现类,服务访问API就会调用服务提供者接口的实现返回对应的服务实例。
这里要说明一点因为服务的实现都是后于JDBC规则出现的,所以想实例化这些对象只能通过反射进行实例化,按照类名进行注册,所以服务提供者接口 的实现负责创建其服务实现的实例。同时使用服务提供者接口进行注册,对于MySQL而言就是Driver。
第一:让我们来看一下MySQL是怎么实现的服务注册:
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是服务提供者接口。
【从JDBC源码带你了解服务提供者框架】其实服务提供者框架作用主要是就是隐藏子类实现,而且可以不断的进行扩展,同时将这些服务整合到一起,使调用者察觉不到子类的不同。
推荐阅读
- 面试|我经历的IT公司面试及离职感受(转)
- java|设计模式——创建型——工厂方法(Factory Method)
- 设计模式|设计模式_创建型模式——工厂方法
- 设计模式|设计模式——创建型软件设计模式——工厂方法模式
- 设计模式之装饰器模式
- 设计模式之设计原则
- 设计模式六大原则(5)(迪米特法则 最少知道)
- 观察者模式实现之EventBus(Google)
- Java高级面试|常见设计模式——装饰模式
- java设计模式——单例模式