双亲委派模型和线程上下文类加载器

最近在读《架构探险-从零开始写java web框架》一书时,看到了一个获取类加载器的地方是这样写的:

     
    public static ClassLoader getClassLoader() {
        return Thread.currentThread().getContextClassLoader();
    }
/**
     * 加载类
     */
    public static Class<?> loadClass(String className, boolean isInitialized) {
        Class<?> cla = null;
        try {
            cla = Class.forName(className, isInitialized, getClassLoader());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return cla;
    }
感觉很奇怪,在的印象里,类加载器只有三种,直接通过本类拿到一个classloader就好了,为什么要获取当前线程的classloader?

Jvm在运行时会产生3个类加载器:

根加载器:由C++编写,在java中不可访问。负责装载JRE核心类库。

ExtClassLoader扩展类加载器:继承根加载器。负责装载JRE的ext目录下的扩展类包。

AppClassLoader应用类加载器:继承扩展类加载器。负责装载ClassPath下的jar包。

类在加载的过程中是遵循全盘负责/委托机制的。

1.全盘负责指使用一个ClassLoader加载类时,除非显示地调用另一个ClassLoader,否则该类所依赖引用的其他由该classLoader加载。

2.委托机制即双亲委派模型,指加载一个类时始终先从父类的父类的父类...直到根装载器(bootstrapClassLoader)寻找目标类,如果启动类加载器没有发现无法加载,便将其交给子类加载,如果子类的子类加载器也无法加载,便会抛出ClassNotFound异常。而且由于双亲委派模型,应用类装载器可以看到启动类装载器所装载的所有的类,而启动类装载器却看不到应用类装载器所装载的类,有点像spring和springMVC的父子容器的bean关系吧?

双亲委派模型不是jvm强制使用的,而是推荐使用的类加载模式,可以保护jre核心类库不被混淆。但这也产生了一些问题。比如在远程方法调用(RMI)中实现 Java 序列化的时候,在从流中反序列化数据为 Java 对象时需要应用的类的相关信息,但是反序列化代码属于jre的核心类库,由启动装载器所装载,而反序列化的java对象则由应用类加载器加载;根据双亲委派模型它也就无法被反序列化的代码访问到。

不仅仅是反序列化会出现问题,在基础类中回调用户代码的操作都会带开这些问题。Java提供了很多服务提供者接口(SPIService Provider Interface),允许独立厂商(第三方)为此提供实现。常见的SPI有:JNDIJDBCJAXP等。这些接口由Java的核心库来提供,所以问题就在于,SPI的接口是Java核心库的一部分,它们是由启动类加载器来加载的。SPI实现的Java类一般是由应用程序类加载器(Application ClassLoader)来加载的。启动类无法找到SPI的实现类,因为它只加载核心库(SPI的实现类由第三方提供)。它也不能代理给应用程序类加载器,因为它又是应用程序类加载器的父类,双亲委派模型又会将它交给启动类来加载。所以在这个时候我们就要“打破”这个“双亲委派模型”。

这个时候线程上下文类加载器就油然而生,它是一个使用ThreadLocal装载classloader的类加载器.

线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader() setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。

它打破了双亲委派模型,直接通过线程上下文类加载器中的类加载器装载指定类。一般来说,在需要动态加载类时,使用线程上下文类加载器,特别适用于开发框架。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值