java双亲委派机制心得1

双亲委派机制,,这是设置出一套规范(并非强制执行和不能破坏),就类似于restful,它是一种规范,你不使用这种规范也可以,但是jdk内部,默认总体逻辑还是按照了双亲委派机制进行了类加载。

举个例子就是,“家族寻宝”--,

你问父亲:我们家族是不是有一个宝藏?

父亲答:我得先问问你爷爷

于是父亲找到你爷爷问:我们家族是不是有一个宝藏?

爷爷答答:我得先问问你爷爷

然后爷爷问你曾爷爷(目前在世的顶层人物):我们家族是不是有一个宝藏?

曾爷爷答你爷爷:有是有,地图给你,我年纪大了不过得你去找。

然后爷爷又对你爸爸说:地图给你,我年纪大了,这个宝藏就交给你去找了

你爸爸找到你说:事情要交给年轻人做,宝藏你去找吧

最后,到你这,你拿着地图去找了宝藏

我想说明的就是这层层的委托,和层层的委派,在询问宝藏的时候,只有到了曾爷爷那才知道有,但是至于谁找宝藏那其实都可以,也可以向下委托

,当然这个例子跟双亲委派有一定的出入,但是也是这样的一种关系,便于大家理解。

我们java程序写完后要编译成class文件,编译成class文件后,到我们jvm中,要使用到对象,那么在这个过程中就涉及到了class文件的加载--加载存储

我们通常说的类的加载过程:

       加载->验证->准备->解析->初始化->使用->卸载,

其中,我们说的双亲委派机制就体现在:加载->验证->准备->解析 过程中

双亲委派机制的

图解如下

bootStrapClassLoader是c写的,看不到具体实现,是加载System.getProperty("sun.boot.class.path")->/jre/lib/rt.jar中的class,并缓存

剩余的加载器都是抽象类ClassLoader的子类(直接或者间接继承)

ExtClassLoader是加载System.getProperty("java.ext.dirs")->/jre/lib/ext/*.jar

AppClassLoader是加载System.getProperty("java.class.path")->当前项目的路径

通常我们自定义类加载器加载外部路径的类,比如网络上的类路径、项目之外的类路径。

虽然ExtClassLoader和AppClassLoader是父子加载器,但并不是类的继承关系

而是通过ClassLoader里的parant属性指定的父子关系。

AppClassLoader的parant=ExtClassLoader

而ExtClassLoader的parant是 null ->即表示bootStrapClassLoader,并不是真的null,只不过是因为实现方式是C;

同样我们自定义类加载器,如果没有指定父加载器,那么默认就是parant=AppClassLoader

那么为什么要采用这样一个机制呢?

我个人的理解主要是为了防止途中有人自定义类加载器,拦截JDK内部类,例如String这些,一旦被篡改,那可能造成灾难级的影响

那么双亲委派机制是怎么避免了这个问题呢?

1,所有的类加载时,先问问父加载器有没有加载,这样一级一级向上,这样去保证了String就先丢给了根加载器去加载

2,所有的类加载器除了根加载器,其他的都是直接或者间接继承了ClassLoad,最后的类加载方法是被private final修饰过了,避免我们去修改他

protected final Class<?> defineClass(String name, byte[] b, int off, int len,

                                     ProtectionDomain protectionDomain)

    throws ClassFormatError

{

    protectionDomain = preDefineClass(name, protectionDomain);

    String source = defineClassSourceLocation(protectionDomain);

    Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);

    postDefineClass(c, protectionDomain);

    return c;

}

3,当我们使用自定义加载器去破坏双亲委派机制时,比如,不优先向上找父加载器,重写loadClass方法,还得去最终findClass当前String类

在时,最终会有个验证阶段,preDefineClass(被private修饰)中去校验当前类是否符合规范-安全,不允许java打头的目录,这样,java.lang.String在验证阶段就被拦截了。

private ProtectionDomain preDefineClass(String name,

                                        ProtectionDomain pd)

{

    if (!checkName(name))

        throw new NoClassDefFoundError("IllegalName: " + name);

    // Note:  Checking logic in java.lang.invoke.MemberName.checkForTypeAlias

    // relies on the fact that spoofing is impossible if a class has a name

    // of the form "java.*"

    if ((name != null) && name.startsWith("java.")) {

        throw new SecurityException

            ("Prohibited package name: " +

             name.substring(0, name.lastIndexOf('.')));

    }

    if (pd == null) {

        pd = defaultDomain;

    }

    if (name != null) checkCerts(name, pd.getCodeSource())

    return pd;

}

自定义类加载器,我们通常也只是重写findClass方法,这样去加载我们目标类(网路路径,或者特定目录下)

当我们重写loadClass时,就很有可能去破坏双亲委派机制,

自定义类加载器、破坏双亲委派机制、实现热加载的总结在之后再整理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值