双亲委派模型以及SpringFactoriesLoader详解

文章目录

前言

前面我们介绍了JavaConfig和常用的Annotation,这一篇文章我们来聊聊SpringFactoriesLoader,在讲SpringFactoriesLoader之前我会先说到JVM的类加载器以及双亲委派模型。闲话少叙,直入主题。

类加载的过程

大致的步骤分为如下几步:

  1. 加载:使用类加载器从不同的地方加载二进制流到方法区
  2. 校验:为了确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求。
  3. 准备:在方法区为静态变量分配内存,并初始化默认值
  4. 解析:将符号引用替换成直接引用,(符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义的定位到目标即可。直接引用可以是 1. 直接指向目标的指针、类变量、类方法;2、相对偏移量;3、一个能间接定位到目标的句柄。)
  5. 初始化:根据静态变量的赋值语法和静态代码块语法,生成一个初始化方法并执行。

类加载器

JVM一共有三种类加载器,分别是:

  1. 启动类加载器(BootstrapClassLoader)加载Java核心类库(%java.home%lib下面的核心类库 或 -Xbootclasspath选项指定的jar包);
  2. 扩展类加载器(ExtClassLoader)加载扩展类库(%java.home%/lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库 );
  3. 应用类加载器(AppClassLoader)加载应用的类路径(用户类路径(java -classpath或-Djava.class.path变量所指的目录)下的类库。
    类的继承关系如下图所示:
    在这里插入图片描述
    JVM通过双亲委派模型进行类的加载,我们可以通过继承java.lang.classLoader实现自己的类加载器。

何为双亲委派模型

当一个类加载器收到类加载任务时,会先交给自己的父加载器去完成,因此最终的加载任务都会传递到最顶层的BootstrapClassLoader(启动类加载器),只有当父加载器无法完成加载任务时,才会尝试自己来加载。事实上,大多数情况下,越基础的类由越上层的加载器进行加载。
其加载流程图如下:
在这里插入图片描述

下面就是ClassLoader类的loadClass方法

ClassLoader类的loadClass方法

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
			//首先,检查该类是否已经被加载,如果从JVM缓存中找到该类,则直接返回。
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
					//遵循双亲委派的模型,首先通过递归从父加载器开始找
					//直到父类加载器是BootstrapClassLoader为止
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) { }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
					//如果还找不到,则尝试通过findClass方法去寻找
					//findClass是留给开发者自己实现的,也就是说自定义类加载器时,
					//重写此方法即可。
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

采用双亲委派的一个好处主要有如下两点:

  1. 防止类被重复加载
    Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层次关系可以避免类被重复加载, 当父类已经加载了该类时,子类就不会再加载一次。保证了使用不同类加载器最终得到的是同一个对象。
  2. 保证核心库的类型安全
    Java核心api中定义的类不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

。。。。。。。。。。。。。。。。。

版权原因,完整文章,请参考如下:双亲委派模型以及SpringFactoriesLoader详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值