很多人看过 Spring 的源码,但但他们都是为了看源码而看!并没有读懂 Spring 的设计思想,也没有思考过为什么要这样设计!
我在这篇文章《程序员如何阅读源码?大牛是如果形成的?》中,已经写到了如何阅读源码。而我的同事按照上面的步骤并结合自身的情况,再过去的几个月看了不少的源码。最终今年破格加薪 2K !
那么接下来我呀说的是,有哪些是你在看源码的过程中并没有注意的细节和内容。比如,今天我们要学习的Spring IOC 容器为什么不使用 Class.forName 加载类,而是使用 ClassLoader!
虽然 Class.forName() 和 ClassLoader 都可用来对类进行加载,但是它们还是有些区别的。为了说明它们,我们来看看 JVM 加载类的步骤是什么!
- 加载:通过类的全限定名获取到类的二进制流, 然后加载到 JVM 中
- 验证:确保Class 文件的字节流中包含的信息符合虚拟机的要求, 并且不会危害虚拟机的安全
- 准备:为类变量分配内存空间并设置类变初始值
- 解析:虚拟机常量池的符号引用替换为字节引用过程
- 初始化:根据用户指定的代码初始化字段和其他资源, 执行 static 块。
清楚上面这个之后,再要想搞明白 Spring Ioc中为什么使用 Classloader,而不是 Class.forName,还得从它们的区别说起。我们先来看看如果使用 Class.forName 会发生什么!
先创建一个测试类。
public class Xttblog { static { System.out.println("www.xttblog.com init."); } } public class Test{ public static void main(String[] args) throws Exception { Class.forName("com.xttblog.Xttblog"); } }
上面的代码中, Class.forName("com.xttblog.Xttblog") 的调用会触发 Xttblog 的静态代码块的执行, 而 ClassLoader.getSystemClassLoader().loadClass("com.xttblog.Xttblog") 并不会。
调用 Class.forName 其实相当于调用了 Class.forName(className, true, currentLoader), 这个方法的第二个参数表示是否需要初始化类。源码中设置为 true, 因此 Class.forName 获取到 Class 对象时, 会自动对类进行初始化的。并且 Class.forName 加载类的 ClassLoader 和调用 Class.forName 所在的类的 ClassLoader 相同。
我们知道 Spring 的 IOC 中有一个懒加载(延迟加载),如果你使用了 Class.forName,那么懒加载这个功能就无法实现了。Spring IoC 为了加快初始化速度,因此大量使用了延时加载技术。而使用 classloader 不需要执行类中的初始化代码,可以加快加载速度,把类的初始化工作留到实际使用到这个类的时候。
所以,Spring IOC 容器并没有采用 Class.forName 来加载类。
: » Spring IOC 容器为什么不使用 Class.forName 加载类
原创文章,作者:wdmbts,如若转载,请注明出处:https://blog.ytso.com/252036.html