java - spring ioc中为什么使用classloader,而不是Class.forName

 潮流时候男装 发布于 2022-10-26 10:25
  • spring ioc中为什么使用classloader,而不是Class.forName
  • 这样使用有什么好处?
  • 这两者有什么本质上的区别?
1 个回答
  • Class.forName 和 ClassLoader.loadClass 的区别

    类加载

    为了弄清楚 Class.forNameClassLoader.loadClass 的区别, 首先我们需要了解 JVM 中类加载的步骤.
    类的加载可以分为如下几步

    • 加载: 通过类的全限定名获取到类的二进制流, 然后加载到 JVM 中

    • 验证: 确保Class 文件的字节流中包含的信息符合虚拟机的要求, 并且不会危害虚拟机的安全

    • 准备: 为类变量分配内存空间并设置类变初始值

    • 解析

    • 初始化: 根据用户指定的代码初始化字段和其他资源, 执行 static 块.

    Class.forName

    当我们通过:

    Class.forName("com.test.MyObj")

    来获取一个 Class 时, 那么其实相当于调用了 Class.forName(className, true, currentLoader), 这个方法的第二个参数表示是否需要初始化类. 我们设置为 true, 因此 Class.forName 获取到 Class 对象时, 会自动对类进行初始化的.
    并且 Class.forName 加载类的 ClassLoader 和调用 Class.forName 所在的类的 ClassLoader 相同.

    ClassLoader.loadClass

    Class.forName 不同, 默认情况下 ClassLoader.loadClass 并不会初始化类, 即类加载的 初始化 步骤没有执行, 因此类中的静态代码块不会执行.
    并且使用 ClassLoader.loadClass 时, 我们可以指定不同的 ClassLoader. 例如:

    ClassLoader.getSystemClassLoader().loadClass("com.test.MyObj");

    一个例子

    public class MyObj {
        static {
            System.out.println("MyObj class init.");
        }
    }
    public class Test implements Cloneable, Serializable {
        public static void main(String[] args) throws Exception {
            Class.forName("com.test.MyObj");
            // ClassLoader.getSystemClassLoader().loadClass("com.test.MyObj");
        }
    }

    那么上面的代码中, Class.forName("com.test.MyObj") 的调用会触发 MyObj 的静态代码块的执行, 而 ClassLoader.getSystemClassLoader().loadClass("com.test.MyObj"); 并不会.

    这样使用有什么好处?

    我个人猜测, 应该和 Spring IoC 的 Lazy loading 有关, Spring IoC 为了加快初始化速度, 因此大量使用了延时加载技术. 而使用 classloader 不需要执行类中的初始化代码, 可以加快加载速度, 把类的初始化工作留到实际使用到这个类的时候.

    2022-10-27 00:55 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有