手机版 欢迎访问it开发者社区(www.mfbz.cn)网站

当前位置: > 开发

实践-验证contextClassLoader的作用

时间:2021/6/10 20:09:46|来源:|点击: 次

前言:关于contextClassLoader的使用场景

基础知识:

类加载机制,双亲委派模式,SPI机制。这里不赘述,不懂的小伙伴们自己补补基础吧~

JDK SPI机制

关于SPI机制可以看下这篇SPI机制

重点关注JDK的SPI机制
其中有提到ServiceLoader#load的源码

public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }

实践

1.目录结构

在这里插入图片描述

如图,service依赖dao,红线框出来的是用到的类。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210610173502991.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaW11eGlhb3hpYW8=,size_16,color_FFFFFF,t_70

相关的代码

1.dao中

public interface ColourConfig {
    String myColour();
}

以下classLoader是抄的网上某大神的代码,出处找不到了,主要是研究contextClassLoader,所以这里的代码没有仔细打磨。

public class MyClassLoader extends ClassLoader {
    private String path ;


    public MyClassLoader(String classPath) {
        path = classPath;
    }
        @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
            Class log = null;
            // 获取该class文件字节码数组
            byte[] classData = getData();

            if (classData != null) {
                // 将class的字节码数组转换成Class类的实例
                log = defineClass(name, classData, 0, classData.length);
            }
            return log;

        }
    private byte[] getData() {

        File file = new File(path);
        if (file.exists()) {
            FileInputStream in = null;
            ByteArrayOutputStream out = null;
            try {
                in = new FileInputStream(file);
                out = new ByteArrayOutputStream();

                byte[] buffer = new byte[1024];
                int size = 0;
                while ((size = in.read(buffer)) != -1) {
                    out.write(buffer, 0, size);
                }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    in.close();
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
            return out.toByteArray();
        } else {
            return null;
        }

    }

    }
public class JavaColorColourFactory {
    public static ColourConfig getColor(){
        ServiceLoader<ColourConfig> colourLoader = ServiceLoader.load(ColourConfig.class);
        Iterator<ColourConfig> colourIterator = colourLoader.iterator();

        ColourConfig colourConfig = null;
        while (colourIterator.hasNext()){
            colourConfig = colourIterator.next();
        }
        return colourConfig;

    }
}

配置文件:

com.dongdong.myheart.service.spi.BlueConfig

2.service模块

public class BlueConfig implements ColourConfig {
    @Override
    public String myColour() {
        return "blue123";
    }
}

3.测试:

@SpringBootTest
class MyheartDaoApplicationTests {

	@Test
	void testContextLoads() {
		try {
			//这里class文件写全路径,我没写全
			MyClassLoader blueClassLoder = new MyClassLoader("**\\BlueConfig.class");
			//看,这里设置了上下文类加载器
			Thread.currentThread().setContextClassLoader(blueClassLoder);
			
			ColourConfig colourConfig = JavaColorColourFactory.getColor();

			Class<?> blueConfig = colourConfig.getClass();
			Method myColour = blueConfig.getMethod("myColour");
			Object blueColour = myColour.invoke(colourConfig);
			ClassLoader factoryClassLoaderReally = JavaColorColourFactory.class.getClassLoader();
			ClassLoader blueClassLoaderReally = colourConfig.getClass().getClassLoader();
			ClassLoader blueParent = blueClassLoaderReally.getParent();
			ClassLoader currentClassLoader = MyheartDaoApplicationTests.class.getClassLoader();
			System.out.println(blueClassLoaderReally);
		}catch (Exception e){
			e.printStackTrace();
		}
	}
}

4.执行结果

在这里插入图片描述

上述可以明显看出,当前测试类以及Factory的类加载器是AppClassLoader,而实现类BlueConfig的类加载器为MyClassLoader,MyClassLoader的parent为AppClassLoader,所以这里是在父类加载器中,加载了子类加载器所加载的类。打破了双亲委派模式。

Copyright © 2002-2019 某某自媒体运营 版权所有