每日一则JavaWeb---ClassLoader原理解析
2017-08-31 16:48
489 查看
参考文档:
参加class对象详解
java中的class对象
深入解析类加载器
对于类的加载机制的探讨主要是最近的Spring源码的第一的解读过程中总是会出现一些很有意思的东西如下:
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}同时最近看到JDBC的接口是在核心类加载器加载的,而实现确实在App类加载器加载的,很相似的一点,都使用了一个连接的容器去连接,在JDBC中使用了CopyOnWriteArrayList而在Spring中使用了ConcurrentHashMap来连接,异曲同工的打破了,双亲委托这种机制的关系。。。。
案例如下:
以mysql为例,介绍一下驱动注册及获取connection的过程:
// 注册驱动类
Class.forName("com.mysql.jdbc.Driver").getInstance();
String url = "jdbc:mysql://localhost:3306/testdb";
// 通过java库获取数据库连接
Connection conn = java.sql.DriverManager.getConnection(url, "name", "password"); 这里就需要了解的是Class.forName的用法了:
它将运行其static静态代码块:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}实实在在的来了,沟通上下游的问题
好,接下来的
这里面就有了这个关键词:获取了当前线程的ClassLoader,
其中线程上下文类加载器的作用已经在上面的注解中详细说明了,获取的Class也就是咱们刚刚看到的Class.forName获取的,其中用
参加class对象详解
java中的class对象
深入解析类加载器
深入探讨 Java 类加载器
真正理解线程上下文类加载器
对于类的加载机制的探讨主要是最近的Spring源码的第一的解读过程中总是会出现一些很有意思的东西如下:ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}同时最近看到JDBC的接口是在核心类加载器加载的,而实现确实在App类加载器加载的,很相似的一点,都使用了一个连接的容器去连接,在JDBC中使用了CopyOnWriteArrayList而在Spring中使用了ConcurrentHashMap来连接,异曲同工的打破了,双亲委托这种机制的关系。。。。
案例如下:
以mysql为例,介绍一下驱动注册及获取connection的过程:
// 注册驱动类
Class.forName("com.mysql.jdbc.Driver").getInstance();
String url = "jdbc:mysql://localhost:3306/testdb";
// 通过java库获取数据库连接
Connection conn = java.sql.DriverManager.getConnection(url, "name", "password"); 这里就需要了解的是Class.forName的用法了:
Class.forName是一个静态方法,同样可以用来加载类。该方法有两种形式:
Class.forName(String name, boolean initialize, ClassLoader loader)和
Class.forName(String className)。第一种形式的参数
name表示的是类的全名;
initialize表示是否初始化类;
loader表示加载时使用的类加载器。第二种形式则相当于设置了参数
initialize的值为
true,
loader的值为当前类的类加载器。
Class.forName的一个很常见的用法是在加载数据库驱动的时候。
Class.forName()加载
com.mysql.jdbc.Driver类,注意该类是
java.sql.Driver接口的实现(
class Driver extends NonRegisteringDriver implements java.sql.Driver),它们名字相同,在下面的描述中将带上package名避免混淆。
它将运行其static静态代码块:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}实实在在的来了,沟通上下游的问题
registerDriver方法将本类(
new com.mysql.jdbc.Driver())注册到系统的DriverManager中,其实就是add到它的成员常量
CopyOnWriteArrayList registeredDrivers中。
好,接下来的
java.sql.DriverManager.getConnection()才算是进入了正戏。它最终调用了以下方法:
private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException { /* 传入的caller由Reflection.getCallerClass()得到,该方法 * 可获取到调用本方法的Class类,这儿调用者是java.sql.DriverManager(位于/lib/rt.jar中), * 也就是说caller.getClassLoader()本应得到Bootstrap启动类加载器 * 但是在上一篇文章中讲到过启动类加载器无法被程序获取,所以只会得到null * 这时问题来了,DriverManager是启动类加载器加载的,可偏偏又要在这儿加载子类的Class * 子类是通过jar包的方式放入classpath中的,由AppClassLoader加载 * 因此这儿通过双亲委派方式肯定无法加载成功,因此这儿借助 * ContextClassLoader来加载mysql驱动类(简直作弊啊!) * 上一篇文章最后也讲到了Thread.currentThread().getContextClassLoader() * 默认set了AppClassLoader,也就是说把类加载器放到Thread里,那么执行方法时任何地方都可以获取到它。 */ 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) { throw new SQLException("The url cannot be null", "08001"); } SQLException reason = null; // 遍历刚才放到registeredDrivers里的Driver类 for(DriverInfo aDriver : registeredDrivers) { // 检查能否加载Driver类,如果你没有修改ContextClassLoader,那么默认的AppClassLoader肯定可以加载 if(isDriverAllowed(aDriver.driver, callerCL)) { try { println(" trying " + aDriver.driver.getClass().getName()); // 调用com.mysql.jdbc.Driver.connect方法获取连接 Connection con = aDriver.driver.connect(url, info); if (con != null) { // Success! return (con); } } catch (SQLException ex) { if (reason == null) { reason = ex; } } } else { println(" skipping: " + aDriver.getClass().getName()); } } throw new SQLException("No suitable driver found for "+ url, "08001"); }
这里面就有了这个关键词:获取了当前线程的ClassLoader,
Class<?> callerClass = Reflection.getCallerClass();
其中线程上下文类加载器的作用已经在上面的注解中详细说明了,获取的Class也就是咱们刚刚看到的Class.forName获取的,其中用
connect()方法获取连接,数据库厂商必须实现该方法,然而调用时DriverManager来加载外部实现类并调用
com.mysql.jdbc.Driver.connect()来获取connection,所以这儿只能拜托Thread中保存的AppClassLoader来加载了,完全破坏了双亲委派模式。
相关文章推荐
- 每日一则JavaWeb---Spring之ContextLoaderListener
- java ClassLoader原理
- 【原创】java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- maven 项目出现 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- maven 项目出现 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderL
- 我的Java开发学习之旅------>Java ClassLoader解析二(转)
- java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener错误解决方案
- maven 报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- maven 项目出现 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- Tomcat 启动报java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener 异常
- java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- maven 项目出现 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- 学习Java的第一步是安装好JDK,写一个Hello World, 其实JDK的学习没有那么简单,关于JDK有两个问题是很容易一直困扰Java程序员的地方:一个是CLASSPATH的问题,其实从原理上来说,是要搞清楚JRE的ClassLoader是如何加
- 深入分析Java ClassLoader原理
- 关于java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoader
- java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderServlet