类加载器顺序-另一种绕开双亲委派的方式(二)通篇改写loadClass

今天对类加载器顺序-另一种绕开双亲委派的方式中的第2种方式做一个实践,基本与JDBC注册原理与自定义类加载器解决com.cloudera.hive.jdbc41.HS2Driver的加载【重点】使用resource中的jar包资源作为UrlClassloader(二)同,主要区别在于

这两篇文章侧重于maven仓库没有的包,意味着系统类加载器无法一上来就加载,没有子加载器想要覆盖父加载器的类的背景,故里面用的是改写findClass,因为这些类不在maven中,不涉及到loadClass双亲委派,findClass即可

 

今天这个实践,是要实验用子加载器加载同名类覆盖掉父加载同名类的表现,从而打破双亲委派,达到类加载器隔离朴实案例的效果

 代码拷贝自使用resource中的jar包资源作为UrlClassloader(二)中2,最主要的两句,@override loadClass + super.loadClass

package lc4;


import java.io.*;
import java.util.HashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import static lc4.FuckPreFindClass.doInvoke;

/**
 * https://www.cnblogs.com/silyvin/articles/12423508.html
 */
public class SafeSon {
    public static void main(String []f) throws Exception {
        String dir = "/Users/sunyuming/Documents/tool/jars//MySub-1.0.0-jar-with-dependencies.jar";
        InputStream url1 = new FileInputStream(dir);
        SunLoadClass sunLoadClass = new SunLoadClass(new JarInputStream[]{new JarInputStream(url1)});
        Class c1 = sunLoadClass.loadClass("lc4.H");
        doInvoke(c1);
        url1.close();
        url1 = new FileInputStream(dir);
        SunFindClass sunFindClass = new SunFindClass(new JarInputStream[]{new JarInputStream(url1)});
        Class c2 = sunFindClass.loadClass("lc4.H");
        doInvoke(c2);
    }
    private static class SunLoadClass extends ClassLoader {

        JarInputStream [] list = null;

        private HashMap<String, byte[]> classes = new HashMap<>();

        public SunLoadClass(JarInputStream [] jarInputStream) {
            this.list = jarInputStream;

            for(JarInputStream jar : list) {
                JarEntry entry;
                try {
                    while ((entry = jar.getNextJarEntry()) != null) {
                        String name = entry.getName();
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        int len = -1;
                        byte [] tmp = new byte[1024];
                        while ((len = jar.read(tmp)) != -1) {
                            out.write(tmp, 0, len);
                        }
                        byte[] bytes = out.toByteArray();
                        classes.put(name, bytes);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            System.out.println("total classes - " + classes.size());

        }

        @Override
        //protected Class<?> findClass(String name) throws ClassNotFoundException {
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            System.out.println("load " + name);
            try {
                InputStream in = getResourceAsStream(name.replace('.', '/') + ".class");
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                int len = -1;
                byte [] tmp = new byte[1024];
                while ((len = in.read(tmp)) != -1) {
                    out.write(tmp, 0, len);
                }
                byte[] bytes = out.toByteArray();
                /**
                 * 三个类都是475长度
                 */
                return defineClass(name, bytes, 0, bytes.length);

            } catch (Exception e) {
                e.printStackTrace();
            }

         //   return super.findClass(name);
            return super.loadClass(name);
        }

        @Override
        public InputStream getResourceAsStream(String name) {
            System.out.println("getResourceAsStream - " + name);
            if(classes.containsKey(name)) {
                byte [] res = classes.get(name);
                /**
                 * define好了就remove掉,否则占堆
                 */
                classes.remove(name);
                return new ByteArrayInputStream(res);
            }
            System.out.println("getResourceAsStream - error - " + name);
            return super.getResourceAsStream(name);
        }
    }
    private static class SunFindClass extends ClassLoader {

        JarInputStream [] list = null;

        private HashMap<String, byte[]> classes = new HashMap<>();

        public SunFindClass(JarInputStream [] jarInputStream) {
            this.list = jarInputStream;

            for(JarInputStream jar : list) {
                JarEntry entry;
                try {
                    while ((entry = jar.getNextJarEntry()) != null) {
                        String name = entry.getName();
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        int len = -1;
                        byte [] tmp = new byte[1024];
                        while ((len = jar.read(tmp)) != -1) {
                            out.write(tmp, 0, len);
                        }
                        byte[] bytes = out.toByteArray();
                        classes.put(name, bytes);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            System.out.println("total classes - " + classes.size());

        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            System.out.println("find " + name);
            try {
                InputStream in = getResourceAsStream(name.replace('.', '/') + ".class");
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                int len = -1;
                byte [] tmp = new byte[1024];
                while ((len = in.read(tmp)) != -1) {
                    out.write(tmp, 0, len);
                }
                byte[] bytes = out.toByteArray();
                /**
                 * 三个类都是475长度
                 */
                return defineClass(name, bytes, 0, bytes.length);

            } catch (Exception e) {
                e.printStackTrace();
            }

            return super.findClass(name);
        }

        @Override
        public InputStream getResourceAsStream(String name) {
            System.out.println("getResourceAsStream - " + name);
            if(classes.containsKey(name)) {
                byte [] res = classes.get(name);
                /**
                 * define好了就remove掉,否则占堆
                 */
                classes.remove(name);
                return new ByteArrayInputStream(res);
            }
            System.out.println("getResourceAsStream - error - " + name);
            return super.getResourceAsStream(name);
        }
    }

}

 

 

 

total classes - 467
load lc4.H
getResourceAsStream - lc4/H.class
load java.lang.Object
getResourceAsStream - java/lang/Object.class
getResourceAsStream - error - java/lang/Object.class
java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at lc4.SafeSon$SunLoadClass.loadClass(SafeSon.java:76)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at lc4.SafeSon$SunLoadClass.loadClass(SafeSon.java:76)
at lc4.SafeSon.main(SafeSon.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
load java.lang.System
getResourceAsStream - java/lang/System.class
getResourceAsStream - error - java/lang/System.class
java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at lc4.SafeSon$SunLoadClass.loadClass(SafeSon.java:76)
at lc4.H.print(H.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lc4.FuckPreFindClass.doInvoke(FuckPreFindClass.java:64)
at lc4.SafeSon.main(SafeSon.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
load java.io.PrintStream
getResourceAsStream - java/io/PrintStream.class
getResourceAsStream - error - java/io/PrintStream.class
java.lang.SecurityException: Prohibited package name: java.io
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at lc4.SafeSon$SunLoadClass.loadClass(SafeSon.java:76)
at lc4.H.print(H.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lc4.FuckPreFindClass.doInvoke(FuckPreFindClass.java:64)
at lc4.SafeSon.main(SafeSon.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
H儿子
load lc4.ByW
getResourceAsStream - lc4/ByW.class
ByW儿子
total classes - 467
H父亲      这个地方:系统类加载器直接加载了,都没进自定义加载器findClass和getResourceAsStream
ByW父亲

posted on 2020-03-05 22:56  silyvin  阅读(337)  评论(0编辑  收藏  举报