Class.forName解析以及使用

2017-01-05 11:09:19来源:oschina作者:二两豆腐人点击

这个类在刚学习Java连接数据库的时候见到这个这种写法,并且工作这么多年,也许是接触的东西比较少,这种用法也就只有在自己手写数据库连接代码的时候见过,在其他的时候还真是没见过。


在Class类中,对此方法有如下声明



方法重载了三次。


查看第一个forName方法的声明为:


@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

首先在这个方法中,使用到了Reflection.getCallerClass(),返回是调用者对象


针对getCallerClass这个方法,这个方法是native的,声明如下:


@CallerSensitive
public static native Class getCallerClass();

由于是native方法,就暂时不跟进去了,这个方法的意思返回调用者 (class对象),也就是说是谁调用调用了我这个类的方法。如下示例:


public class ReflectionCaller {
public static void main(String[] args) {
InnerClass i = new InnerClass();
i.innerMethod();
}
}
class InnerClass {
public void innerMethod() {
System.out.println(Reflection.getCallerClass());
}
}

运行以上代码,输出的结果是:



也就是ReflectionCaller这个类对象。这个方法还是比较有趣的,如果在以后我们自己写代码的时候,想知道谁在调用我这些的这些方法,就可以跟踪出来了。


获取调用者信息以后,会调用Class.forname0方法,进行加载和初始化类。看到forname0这个方法又是一个native方法。


private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;

这个方法的作用是根据name加载传递过来的类,并且根据initialize来决定是否要进行初始化,所谓初始化指的是加载里面的静态块之类的。加载的时候采用caller相同的类加载器记性加载。

从中可以看出Class.forName和Classloader.lodeclass的区别是什么,Class.forName可以加载类并且控制是否要对类进行初始化,而ClassLoader.loadClass只对类进行加载,不进行初始化。

知道了Class.forName 的作用,那接下来就看一下针对连接mysql的具体问题。


根据第一节,可以看到连接字符串为:


Class.forName("com.mysql.jdbc.Driver");


也就是说会加载com.mysql.jdbc.Driver这个类,并且进行初始化。找到mysql-connector-java.jar的源码,这个类非常简单。


public class Driver extends NonRegisteringDriver implements java.sql.Driver {
//
// Register ourselves with the DriverManager
//
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
/**
* Construct a new driver and register it with DriverManager
*
* @throws SQLException
*if a database error occurs.
*/
public Driver() throws SQLException {
// Required for Class.forName().newInstance()
}
}

这个类中 就一个静态块和一个无参的构造函数,通过静态块的内容可以看出,实例了的一个Driver,然后注册到DriverManager,DriverManager把这个Driver存储到了一个CopyOnWriteArrayList中。


同时Driver还继承了AbandonedConnectionCleanupThread这个类,这个类继承Thread,启动一个守护线程,然后清理废弃的类对象。


以上就是我们在连接mysql时,Class.forName的功能。但是需要注意的是 Java 的SQL框架允许多个数据库的Driver,每一个Driver都要实现java.sql.Driver接口,针对给出来的连接数据库的请求,DriverManager尝试去load尽可能多的它找到的drivers,然后根据这些driver尝试使用给出来的数据库连接字符串去尝试连接数据库。 在mysql的NonRegisteringDriver中强烈建议,每个驱动程序类应该尽可能的小和独立,这样再加载和查询驱动类的时候,才不会引入大量的支持代码。


最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台