服务提供者框架+JDBC驱动源码分析

本文详细介绍了服务提供者框架的概念与应用,并通过JDBC的实现案例进行深入解析。阐述了框架的基本组成及工作原理,包括服务接口、提供者接口、注册API和服务访问API等关键部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

服务提供者框架+JDBC驱动源码分析

1.服务提供者框架介绍

  服务提供者框架是指这样一个系统:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来。
  例如,JDBC mySQL和JDBC Oracle,两种驱动,我们使用的时候,只需要简单的注册驱动然后getConnection就能得到Connection对象,其实这两个驱动有不同的实现,如连接两个数据库的方式不同,但我们使用的时候,不用区别就能得到Connection服务接口。
  服务者提供框架有四个组件:

  • 服务接口:服务的实现,由提供者实现
  • 提供者注册API:注册驱动,让客户端能访问
  • 服务访问API:驱动内实现,客户端获取服务接口
  • (可选)服务提供者接口: 负责创建服务实现的实例

2.简单的代码框架

//服务提供者框架简述
**//服务接口**
public interface Service {
    ...//定义提供哪些服务
}
**//服务提供者接口 负责创建实例**
public interface Provider {
    Service.newInstance();//自定义服务,负责创建实例返回
}
//服务注册以及获取接口
public class Services {
    private Services () { }//不能实例化
    //保存服务提供者的实例
    private static final Map<String,Provider> providers = 
        new ConcurrentHashMap<String,Provider>();
    private static final String DEAFULT_PROVIDER_NAME = "<def>";
    **//服务提供者注册API**
    public static void registerDefaultProvider(Provider p){
        registerProvider(DEAFULT_PROVIDER_NAME, p);
    }
    public static void registerProvider(String name, Provider p){
        providers.put(name, p);
    }
    **//服务访问API**
    public static Service getService(){
        return newInstance(DEAFULT_PROVIDER_NAME);
    }
    public static Service getService(String name){
        Provider p = providers.get(name);
        if( p == null){
            throw new IllegalArgumentException(
            "No provider registered with name: " + name );
        }
        return p.newService();
    }
}

  Service是一个服务接口,定义服务有哪些功能要实现,Provider是一个服务提供者接口,负责实现服务接口定义的功能,并实例化服务接口,Services 注册服务提供者(registerProvider),通过名称映射保存服务提供者的实例,同时提供服务访问的接口(getService)。当我们想要使用Service定义的功能时,我们只需要注册服务提供者,然后getService就可以得到服务实例。这样就使得Provider1,Provider2能定义不同的实现,来提供相同的服务,而我们在使用的时候,是感受不到Service实现不同的。这就是服务提供者框架的好处。

3.JDBC mySQL的应用

  使用JDBC mySQL得到数据库的连接,并执行得到数据库放回结果,整个过程的代码如下:

public class JDBCCon {
    private Connection conn = null;
    private PreparedStatement pstmt = null;
    private ResultSet rs = null;
    private String sql = "SELECT * FROM table WHERE id = ? ";

    public void selectTable (int id){
        try{
            //STEP1: 加载数据库驱动程序
            Class.forName("com.mysql.jdbc.Driver");
        }catch (ClassNotFoundException e){e.printStackTrace(); }
        String url = "jdbc:mysql://localhost:port/DB_Name";
        try{
            //STEP2: DriverManager获得一个数据库连接对象
            conn = DriverManager.getConnection(url,"userName","password");
        }catch(SQLException e){ e.printStackTrace(); }
        try{
            //STEP3: 创建Statement(SQL执行环境)
            pstmt = conn.prepareStatement(sql);
            pstmt = setInt(1, id);
            //STEP4: 执行SQL语句
            rs = pstmt.executeQuery();
            //STEP5 : 处理结果
            while(rs.next() ){ /*......*/ }
        }catch (SQLException e) { e.printStackTrace(); }
        finally{ 
            //STEP6: 关闭数据库连接 
            DbClose.close(rs,pstmt, conn);
        }
    }
}

  java.sql.Connection对象就是服务接口,从服务框架来说,step1注册服务提供者,step2得到服务接口对象,step3使用服务提供的功能,我们不用区分JDBC mySQL和JDBC Oracle的实现的不同,就能调用方法得到相同的Connection服务。接下来会从mySQL JDBC源码执行路径,来解析step1和step2的执行过程。

4.STEP1:Class.forName如何注册驱动

Class.forName("com.mysql.jdbc.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!");
        }
    }
    //Constructors
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}
public class DriverManager {
    /* write copy of the drivers vector */
    private static java.util.Vector writeDrivers = new java.util.Vector();
    /* write copy of the drivers vector */
    private static java.util.Vector readDrivers = new java.util.Vector();

    public static synchronized void registerDriver(java.sql.Driver driver)
    throws SQLException {
        DriverInfo di = new DriverInfo();
        di.driver = driver;
        di.driverClass = driver.getClass();
        di.driverClassName = di.driverClass.getName();
        // Not Required -- drivers.addElement(di);
        **writeDrivers.addElement(di);** 
        println("registerDriver: " + di);
        /* update the read copy of drivers vector */
        readDrivers = (java.util.Vector) writeDrivers.clone();
    }
}
//这里有个疑问,为什么DriverManager要使用两个vector去保存driver实例?

  通过Class.forName(“com.mysql.jdbc.Driver”)来加载mysql的jdbc驱动,通过静态初始化块在DriverManager中注册自己(驱动信息封装成DriverInfo驱动信息类,加入集合中)。 Mysql的com.mysql.jdbc.Driver类实现了java.sql.Driver接口,任何数据库提供商的驱动类都必须实现这个接口。在DriverManager类中使用的都是接口Driver类型的驱动,也就是说驱动的使用不依赖于具体的实现,这无疑给我们的使用带来很大的方便。如果需要换用其他的数据库的话,只需要把Class.forName()中的参数换掉就可以了,可以说是非常方便的.

5.STEP2:DriverManager.getConnection

  获取数据库的连接本质其实就是客户端取得一个远程MySQL服务器的TCP长连接。

DriverManager.getConnection(url,"userName","password");
public class DriverManager {
    //not only one public getConnection method ,see more in standard source code
    public static Connection getConnection(String url, 
    String user, String password) throws SQLException {
        java.util.Properties info = new java.util.Properties();
        ClassLoader callerCL = DriverManager.getCallerClassLoader();
        if (user != null) { info.put("user", user );  }
        if (password != null) { info.put("password", password); }
        return (getConnection(url, info, callerCL));
    }

    //  Worker method called by the public getConnection() methods.
    private static Connection getConnection(
    String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
        java.util.Vector drivers = null;

        if(url == null) { 
            throw new SQLException("The url cannot be null", "08001"); }
        println("DriverManager.getConnection(\"" + url + "\")");

        drivers = readDrivers;//源码中有同步锁,这里简写了
        SQLException reason = null;
        for (int i = 0; i < drivers.size(); i++) {
            DriverInfo di = (DriverInfo)drivers.elementAt(i);

            if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
                println("    skipping: " + di); continue;
            }
            try {
                println("    trying " + di);
                Connection result = di.driver.connect(url, info);//这个方法的实现在NonRegisteringDriver
                if (result != null) {
                    // Success!
                    println("getConnection returning " + di);
                    return (result);
                }
            } catch (SQLException ex) {
                if (reason == null) { reason = ex; }
            }
        }

        // if we got here nobody could connect.
        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");
    }
}
public class NonRegisteringDriver implements java.sql.Driver {
    public java.sql.Connection connect(String url, Properties info)
            throws SQLException {
        //省略一些前缀匹配,实现不同的url类型,分别处理
        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) { throw sqlEx;
        } catch (Exception ex) { throw SQLError.createSQLException("..."); }
    }
}

public class Connection extends ConnectionProperties implements 
            java.sql.Connection {
    Connection(String hostToConnectTo, int portToConnectTo, Properties info,
            String databaseToConnectTo, String url) throws SQLException {
        //这个方法代码很多,挑了两句重点的理解一下
        //初始化驱动的属性信息....
        initializeDriverProperties(info);
        createNewIO(false);//创建新的连接服务器的IO channel
    }
}
//私有的getConnection方法中有synchronized(DriverManager.class){}有什么作用?
 protected void createNewIO(boolean isForReconnect)  
        throws SQLException {  
        // 创建一个MysqlIO对象,建立与Mysql服务器的Socket连接   
        this.io = new MysqlIO(newHost, newPort, mergedProps, 
                getSocketFactoryClassName(), this,  
        getSocketTimeout(),  
         this.largeRowSizeThreshold.getValueAsInt());  
       // 登录校验MySql Server, 发送用户名、密码、当前数据库连接默认选择的数据库名
       this.io.doHandshake(this.user, this.password,  
                                 this.database);
        // 获取MySql数据库连接的连接ID
       this.connectionId = this.io.getThreadId(); 
       this.isClosed = false;  
 }

  在集合中,找到注册的驱动,在createNewIO方法中去执行连接数据库的步骤。

6.总结

  Connection是服务接口,driver是服务提供者接口,DriverManager.registerDriver是提供者注册API,DiverManager.getConnection是服务访问API。emmmmm.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值