JDBC中Class.forName到底做了什么以及相关设计模式
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了JDBC中Class.forName到底做了什么以及相关设计模式,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4975字,纯文字阅读大概需要8分钟。
内容图文
JDBC操作数据库时我们第一步是调用Class.forName注册数据库驱动
public class Test { public static void main(String[] args) throws ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","rootroot"); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("select * from user where id = 1"); while (resultSet.next()){ String name = resultSet.getString("name"); System.out.println(name); } } }
为什么调用Class.forName就能够把驱动加载进来呢?第一反应是看forName方法做了什么操作
/** * Returns the { @code Class} object associated with the class or * interface with the given string name. Invoking this method is * equivalent to: * * <blockquote> * { @code Class.forName(className, true, currentLoader)} * </blockquote> * *返回与给定字符串名的类或接口相关联的{ @code Class}对象。调用这个方法相当于:Class.forName(className, true, currentLoader) */ @CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
从注释可以得出forName(String className)是会初始化类的,也就是说类中的静态变量和静态代码块会被执行,所以com.mysql.jdbc.Driver类将会被加载并初始化
public class Driver extends NonRegisteringDriver implements java.sql.Driver { public Driver() throws SQLException { } static { try { // 这里把自己注册了 DriverManager.registerDriver(new Driver()); } catch (SQLException var1) { thrownew RuntimeException("Can‘t register driver!"); } } }
查看Driver源码也证实了这点,就是在类被加载时在静态代码块初始化了Driver对象。DriverManager.registerDriver(new Driver) 等价于Class.forName("com.mysql.jdbc.Driver")。到此我们便清楚的知道了驱动类是怎么被加载的。
接下来我们再看DriverManager.registerDriver方法,看看究竟数据库驱动是怎么被注册和使用的
// List of registered JDBC drivers private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>(); /** * Registers the given driver with the {@code DriverManager}. * A newly-loaded driver class should call * the method {@code registerDriver} to make itself * known to the {@code DriverManager}. If the driver is currently * registered, no action is taken. * * @param driver the new JDBC Driver that is to be registered with the * {@code DriverManager} * @param da the {@code DriverAction} implementation to be used when * {@code DriverManager#deregisterDriver} is called * @exception SQLException if a database access error occurs * @exception NullPointerException if {@code driver} is null * @since 1.8 */publicstaticsynchronizedvoid registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException { /* Register the driver if it has not already been added to our list */if(driver != null) { registeredDrivers.addIfAbsent(new DriverInfo(driver, da)); } else { // This is for compatibility with the original DriverManagerthrownew NullPointerException(); } println("registerDriver: " + driver); }
从源码里我们可以清晰的看到被new的driver对象被加到了一个list中。注册好驱动下一步则是获取连接Connection
// Worker method called by the public getConnection() methods. private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException { /* * When callerCl is null, we should check the application‘s * (which is invoking this class indirectly) * classloader, so that the JDBC driver class outside rt.jar * can be loaded from here. */ ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; synchronized(DriverManager.class) { // synchronize loading of the correct classloader.if (callerCL == null) { callerCL = Thread.currentThread().getContextClassLoader(); } } if(url == null) { thrownew SQLException("The url cannot be null", "08001"); } println("DriverManager.getConnection(\"" + url + "\")"); // Walk through the loaded registeredDrivers attempting to make a connection. // Remember the first exception that gets raised so we can reraise it. SQLException reason = null; 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()); // 这里利用注册进来的driver对象创建了连接对象 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; } } } else { println(" skipping: " + aDriver.getClass().getName()); } } // if we got here nobody could connect.if (reason != null) { println("getConnection failed: " + reason); throw reason; } println("getConnection: no suitable driver found for "+ url); thrownew SQLException("No suitable driver found for "+ url, "08001"); }
实际上获取连的是被注册进去的com.mysql.jdbc.Driver创建的。分析这几个类可以看出JDBC使用了桥接模式来达到接口与具体实现的分离。所以我们能够随意的变化底层数据库,但是jdbc的使用方法不变,唯一变的仅仅是注册时的驱动而已,jdbc通过桥接模式将接口已经规范好了,而具体的实现则由具体数据库决定。
原文:https://www.cnblogs.com/zh-ch/p/12825129.html
内容总结
以上是互联网集市为您收集整理的JDBC中Class.forName到底做了什么以及相关设计模式全部内容,希望文章能够帮你解决JDBC中Class.forName到底做了什么以及相关设计模式所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。