解决: it should be loaded by xxxClassLoader

背景描述:

使用mockito写单元测试类时报错:it should be loaded by xxxClassLoader.

解决方法:使用sun.misc.Unsave解决某些类需要特定类加载器加载。

上代码:

先写个工具方法

	private sun.misc.Unsave getUnsafe(){
        Unsafe unsafe = null;
        try {
            // 反射拿到内部的私有的实例化单例对象
            Field field = sun.misc.Unsave.class.getDeclaredField("theUnsafe");
            // 暴力获取
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return unsafe;
    }

写测试方法

假设该update方法内部需要调用一个静态的、且只能由jar包中特定类加载器加载的日志方法OkLog.get,

该方法内部会检测是否由正确的类加载器加载,否则报错。

	// 伪代码
	@Test
    public void testUpdate() throws InstantiationException {
		// 一些常规操作
		// when(..).then...
		// when(..).then...
		// 关键操作如下

		// 因为是静态方法,无法直接when,所以先mock出类
		MockedStatic<OakLog> okLogMockedStatic = mockStatic(OkLog.class);
		// 是用Unsafe直接构造对象
		OkLog o = (OkLog) getUnsafe().allocateInstance(OkLog.class);
		// 这里可以when了
		when(OkLog.get()).thenReturn(o);

		// ...
		//	调用被测方法
		int i = userService.update(user);
		// ...
		
		// 别忘了清除okLogMockedStatic
		oakLogMockedStatic.close();
	}
后记

unsafw类比较危险,轻易不建议使用

allocateInstance()方法底层是操作jvm直接分配内存空间并返回一个Object类的实例,该实例的所有字段都为默认值。该方法创建对象时,不会掉用任何构造方法,所以需要注意构造方法中的一些初始化操作并不会执行。

allocateMemory()方法会直接在堆外内存申请一块连续的内存,使用完毕后需要调用freeMemory()方法手动回收内存,该方法传入的是long类型的内存地址起始值,getLong方法获取的是对象的起始内存地址

public native void freeMemory(long address);

该方法接收一个long类型的参数address,表示要释放的内存块的起始地址。在调用该方法时,Unsafe类会将指定地址开始的连续内存块释放,这样这些内存块就可以被其他对象或操作使用了。

public native long getLong(Object o, long offset);

该方法接收两个参数,第一个参数o表示要获取的对象,第二个参数offset表示对象内存空间中的偏移量,该方法也就是要获取的字段在对象内存空间中的位置。

注意⚠️

Unsafe类的方法通常是不安全的,因为它们可以直接访问内存空间,可能会导致内存泄漏或内存溢出等问题。因此,在使用Unsafe类时需要格外小心,并遵循相关的安全规范和最佳实践,以避免潜在的安全风险和性能问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值