实践-验证contextClassLoader的作用

前言:关于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,红线框出来的是用到的类。
在这里插入图片描述

相关的代码

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();
		}
	}
}

以上class的全路径,我是直接编译后找到的target目录下,右键copy path获得的全路径
在这里插入图片描述

4.执行结果

在这里插入图片描述

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值