专栏首页技术趋势如何打破双亲委派机制?

如何打破双亲委派机制?

上文:jdk-Launcher源码学习


背景

上文说过,jdk是通过双亲委派机制实现类的加载,但是这个加载效率及场景存在弊端,所以本文借鉴tomcat的实现方式去打破双亲委派机制实现自定义类加载器来模似tomcat的类加载方式。

实现方式

实现思想:首先继承ClassLoader,然后通过classLoader进行重写findClass实现。

package com.classloader.simulate;

import com.encryption.demo.EncryptionUtils;
import org.apache.commons.lang.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author hong
 * @version 1.0
 * @description: 模似打破双亲委派机制
 * @date 2022/4/16 18:50
 */
public class SimulateTomcatClassLoader  {

    static class MySelfClassLoader extends ClassLoader{
        /**
         * 类路劲
         **/
        private String classPath;

        public MySelfClassLoader(String classPath) {
            this.classPath = classPath;
        }

        private byte[] loadByClassName(String className) throws Exception {
            if (StringUtils.isEmpty(className)) {
                throw new Exception("类名不能为空!");
            }
            //替换路劲格式
            className = className.replaceAll("\\.", "/");
            //获取文件信息
            FileInputStream fis = new FileInputStream(classPath + "/" + className + ".class");
            //获取长度
            int len = fis.available();
            //文件信息
            byte[] data = new byte[len];
            //读写文件信息
            fis.read(data);
            fis.close();
            return data;

        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByClassName(name);
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

        /**
         * 重写类加载方法,在这里打破双亲委派
         * @param name
         * @param resolve
         * @return
         * @throws ClassNotFoundException
         */
        @Override
        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    //这里重写逻辑 如果不是自定义类开头就用默认类加载器,如果是就有自定义类加载器加载
                    if(!name.startsWith("com.classloader")){
                        c = this.getParent().loadClass(name);
                    }else{
                        c = findClass(name);
                    }

                    // this is the defining class loader; record the stats
// sun.misc.PerfCounter.getParentDelegationTime().addTime(t1);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
// }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }


    public void test(){
        System.out.println("测试类!");
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //获取项目路劲
        File file = new File(EncryptionUtils.class.getResource("/").getPath());
        MySelfClassLoader mySelfClaasLoader = new MySelfClassLoader(file.getPath());
        Class<?> loadClass = mySelfClaasLoader.loadClass("com.classloader.simulate.SimulateTomcatClassLoader");
        //获取实例对象
        Object obj = loadClass.newInstance();
        //获取方法列表
        Method[] declaredMethods = loadClass.getDeclaredMethods();
        System.out.println(declaredMethods);
        //获取方法
        Method method = loadClass.getMethod("test", null);
        method.invoke(obj,null);
        System.out.println(loadClass.getClassLoader().getClass().getName());;
    }
}

结果

测试类!
com.classloader.simulate.SimulateTomcatClassLoader$MySelfClassLoader

最后

很多容器都是打破Jvm的双亲委派机制来实现的,比如tomcat,如果不打破的话根据无法部署多个项目,所以打破双亲委派机制也是一种业务场景的需要。而通过了解和实现打破双亲委派机制来学习tomcat的实现,有效提升对jvm底层的实现了解。

参考文章:

https://www.jianshu.com/p/7706a42ba200

https://cwiki.apache.org/confluence/display/tomcat/FAQ

https://blog.csdn.net/lisheng5218/article/details/111475536

文章分享自微信公众号:
技术趋势

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:逍遥壮士
原始发表时间:2022-04-30
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 双亲委派机制及打破双亲委派示例

    在加载类的时候,会一级一级向上委托,判断是否已经加载,从自定义类加载器-》应用类加载器-》扩展类加载器-》启动类加载器,如果到最后都没有加载这个类,则回去加载自...

    全栈程序员站长
  • 1.4 打破双亲委派机制

    比如, 我现在有一个自定义类加载器, 加载的是~/com/lxl/jvm/User1.class类, 而在应用程序的target目录下也有一个com/lxl/...

    用户7798898
  • 1.5 tomcat是如何打破双亲委派机制的?

    首先, 来举个例子, 通常,一个tomcat要加载几个应用程序呢? 当然是n多个应用程序, 加入我们使用的都是spring的框架, 那我们能保证所有的应用程序都...

    用户7798898
  • Java打破双亲委派机制「建议收藏」

    沿用双亲委派机制自定义类加载器很简单,只需继承ClassLoader类并重写findClass方法即可。 ①先定义一个待加载的类Test,它很简单,只是在构...

    全栈程序员站长
  • JVM – 彻底理解打破双亲委派机制

    我们希望通过自定义加载器 直接从某个路径下读取Artisan.class . 而不是说 通过自定义加载器 委托给 AppClassLoader ——> ExtC...

    全栈程序员站长
  • JVM - 彻底理解打破双亲委派机制

    我们希望通过自定义加载器 直接从某个路径下读取Artisan.class . 而不是说 通过自定义加载器 委托给 AppClassLoader ------> ...

    小小工匠
  • Tomcat如何打破双亲委派机制实现隔离Web应用的?

    Tomcat通过自定义类加载器WebAppClassLoader打破双亲委派,即重写了JVM的类加载器ClassLoader的findClass方法和loadC...

    JavaEdge
  • Tomcat如何打破双亲委派机制实现隔离Web应用的?

    Tomcat通过自定义类加载器WebAppClassLoader打破双亲委派,即重写了JVM的类加载器ClassLoader的findClass方法和loadC...

    JavaEdge
  • 双亲委派机制

    孙晨c
  • Tomcat如何打破双亲委托机制?

    我们经常会遇到ClassNotFound异常,表明JVM在尝试加载某类时失败了。 要解决这个异常,你得知道

    JavaEdge
  • JVM - 双亲委派机制

    父加载器不是“类加载器的父类加载器”!!! 双亲委派是一个孩子向父亲(上级)方向,然后父亲向孩子方向的双亲委派过程

    Parker
  • Tomcat如何打破双亲委托机制?

    我们经常会遇到ClassNotFound异常,表明JVM在尝试加载某类时失败了。 要解决这个异常,你得知道

    JavaEdge
  • 面试官:说说如何打破或违反双亲委派!

    SPI的全名为Service Provider Interface,主要是应用于厂商自定义组件或插件中,在java.util.ServiceLoader的文档里...

    业余草
  • 类加载:双亲委派机制

    类从被加载到虚拟机开始,到卸载出内存为止,它的整个的生命周期包括:加载、连接(验证、准备、解析)、初始化、使用和卸载七个阶段。

    chenchenchen
  • 为何采用双亲委派机制

    java中存在3种类型的类加载器:引导类加载器,扩展类加载器和系统类加载器。三者是的关系是:引导类加载器是扩展类加载器的父类,扩展类加载器是系统类加载器的父类。

    allsmallpig
  • 带你搞懂双亲委派机制

    之前详细介绍了Java类的整个加载过程(类加载机制你真的了解吗?)。虽然,篇幅较长,但是也不要被内容吓到了,其实每个阶段都可以用一句话来概括。

    烟雨星空
  • 类加载机制 双亲委派模型

    当一个类收到了类加载请求时: 自己不会首先加载,而是委派给父加载器进行加载,每个层次的加载器都是这样。

    爱明依
  • Tomcat 类加载器打破双亲委派模型

    1. 什么是类加载机制? 2. 什么是双亲委任模型? 3. 如何破坏双亲委任模型? 4. Tomcat 的类加载器是怎么设计的?

    爱撸猫的杰
  • 【高级开发进阶】1.1.3 双亲委派模型及如何打破

    双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。

    Java廖志伟

扫码关注腾讯云开发者

领取腾讯云代金券