【JVM之打破双亲委派】

Jvm之打破双亲委派

1. 双亲委派

// ClassLoader中的方法
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);
            // null,表示没有加载过
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                    	// 递归调用父加载器的loadClass
                        c = parent.loadClass(name, false);
                    } else {
                    	// 如果没有了parentClassloader,说明到了BootstrapClassLoader这一层
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                    // class没有找到就会抛出ClassNotFoundException(从非空父加载器)
                }
				// 如果为空,调用每一层的findClass去找
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    // 每次都做一些记录
                    PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

2.打破双亲委派

/*
	可见想要打破双亲委派,就是不要调用此loadClass,可以自定一个实现,重写其逻辑。
	或者自定义classLoader,加载类,然后重写findClass(重写find机制-缓存等)返回自定义
	classLoader加载的类。
*/
public class MyClassLoader extends URLClassLoader {
    public MyClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name.startsWith("com.mysql")) {
            System.out.println("进来了,打破双亲委派啦");
            // 如果类名以指定的包名开头,自己加载
            return findClass(name);
        } else {
            // 否则委托给父类加载器加载
            return super.loadClass(name);
        }
    }


    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        File file = new File("D:\\Application\\MavenRepo\\com\\mysql\\mysql-connector-
        					j\\8.0.33\\mysql-connector-j-8.0.33.jar");
        try (JarFile jarFile = new JarFile(file)) {
            JarEntry entry = jarFile.getJarEntry(name.replace(".", "/") + ".class");
            if (entry != null) {
                try (InputStream is = jarFile.getInputStream(entry)) {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    int len;
                    byte[] buffer = new byte[4096];
                    while ((len = is.read(buffer)) != -1) {
                        baos.write(buffer, 0, len);
                    }
                    byte[] data = baos.toByteArray();
                    return defineClass(name, data, 0, data.length);
                }
            }
        } catch (IOException e) {
            throw new ClassNotFoundException("Error loading class " + name, e);
        }
        throw new ClassNotFoundException(name);
    }
}

public class Test{
	public static void main(String[] args) throws Exception {
        File file = new File("D:\\Application\\MavenRepo\\com\\mysql\\mysql-connector-
        				j\\8.0.33\\mysql-connector-j-8.0.33.jar");
        URL url = file.toURI().toURL();
        MyClassLoader loader = new MyClassLoader(new URL[]{url}, 
        	Thread.currentThread().getContextClassLoader());
        System.out.println("thread.currentThread.contextClassLoader: " + 
        			Thread.currentThread().getContextClassLoader());
        Class<?> driverClass = loader.loadClass("com.mysql.cj.jdbc.Driver");
        System.out.println("classLoader: " + driverClass.getClassLoader());
        Connection connection = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/test",
                "root", "root"
        );
        System.out.println(connection);
        PreparedStatement pdst = connection.prepareStatement("select * from users;");
        ResultSet rs = pdst.executeQuery();
        while (rs.next()) {
            int userid = rs.getInt("userid");
            String username = rs.getString("username");
            String usersex = rs.getString("usersex");
            System.out.println("userid=" + userid + ", username=" + username + ",
            					 usersex=" + usersex);
        }
        rs.close();
        connection.close();
    }
}

/*
	thread.currentThread.contextClassLoader: 
						jdk.internal.loader.ClassLoaders$AppClassLoader@7b1d7fff
	进来了,打破双亲委派啦
	进来了,打破双亲委派啦
	classLoader: cn.gbase.admin.plugin.controller.MyClassLoader@31dc339b
	com.mysql.cj.jdbc.ConnectionImpl@37e4d7bb
	userid=1, username=张三, usersex=男
	userid=2, username=李四, usersex=男
	userid=8, username=袁婷, usersex=女
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值