从JDBC源码带你了解服务提供者框架

来源:互联网 发布:地下室 知乎 编辑:程序博客网 时间:2024/05/26 17:48

工作一年,一直想写博客记录和分享一些想法,做一名分享的Coder,尽力去写一些高质量的博文。希望能够坚持下去,对博文有建议或意见的朋友们可以联系我。

个人邮箱:zhangshaoqiangchn@gmail.com

前言:

首先让我们回忆一下在编写JDBC代码的时候,我们在获取Connection的时候怎么获取的

        Class.forName("com.mysql.jdbc.Driver");        Connection connection= DriverManager.getConnection("jdbc:mysql:///mydatabase", "root", "root");
  1. 通过反射的方式将com.mysql.jdbc.Driver的class文件通过类加载器加载到内存中
  2. 通过DriverManager得到Connection

第一步我们通常叫注册驱动,那什么叫做注册驱动?都是通过什么实现的注册驱动呢?下面让我们带着问题去了解服务提供框架。


定义:

多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。——–《Effective Java》

组件:

  1. 服务接口(Service Interface):提供者去实现的。
  2. 提供者者注册API(provider Registration API):系统用来注册实现的。
  3. 服务访问API(Service Access API):客户端用来获取实例的。
  4. 服务提供者API(Service Provider Interface)(可选):创建其服务实例对象的。

实际场景:

sun公司在制定JDBC这套规则的时候,如果MySQL还没有出现,sun公司会再给MySQL重新制定一套规则吗?一定不会吧,可是这个问题怎么解决?

步骤:

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<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();    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是服务提供者接口

其实服务提供者框架作用主要是就是隐藏子类实现,而且可以不断的进行扩展,同时将这些服务整合到一起,使调用者察觉不到子类的不同。

2 0
原创粉丝点击