1.mockito源码解析-创建mock对象的过程

mockito创建mock对象的方式:

List list = mock(List.class);

现在我们来看看,这行代码到底在干什么?

(1)Mockito.java


	/**
	 * 创建一个mock实例
	 *
	 * @param classToMock  需要mock的接口或者类
	 */
	public static <T> T mock(Class<T> classToMock) {
		// [1]
		return mock(classToMock, withSettings().defaultAnswer(RETURNS_DEFAULTS));
	}
	
	public static <T> T mock(Class<T> classToMock, MockSettings mockSettings) {
		// 调用MockitoCore.mock方法
		return MOCKITO_CORE.mock(classToMock, mockSettings);
	}
		

[1] withSettings()返回的是mock的配置对象,由于配置对象包含的信息比较多,会在后面一一介绍。

(2)MockitoCore.java

	/**
	 * 创建一个mock实例
	 *
	 * @param typeToMock  需要mock的接口或者类
	 * @param settings mock对象创建的配置
	 */
	public <T> T mock(Class<T> typeToMock, MockSettings settings) {
		if (!MockSettingsImpl.class.isInstance(settings)) {
		// 要求配置对象是MockSettingsImpl的实例
			throw new IllegalArgumentException(
					"Unexpected implementation of '" + settings.getClass().getCanonicalName() + "'\n"
					+ "At the moment, you cannot provide your own implementations that class.");
		}
		// cast判断类型,其实上面的已经处理了,这里相当于强转
		MockSettingsImpl impl = MockSettingsImpl.class.cast(settings);
		// 校验配置对象(以后介绍)
		MockCreationSettings<T> creationSettings = impl.confirm(typeToMock);
		// [2]
		T mock = mockUtil.createMock(creationSettings);
		// [3]
		mockingProgress.mockingStarted(mock, typeToMock);
		return mock;
	}

[2] 在此之前就是创建配置和校验配置操作,而mockUtil.createMock就是真正创建mock对象的方法

MockUtil.java

    public <T> T createMock(MockCreationSettings<T> settings) {
        // [4]
        MockHandler mockHandler = new MockHandlerFactory().create(settings);
        // [5]
        T mock = mockMaker.createMock(settings, mockHandler);
        // 说到spy在介绍
        Object spiedInstance = settings.getSpiedInstance();
        if (spiedInstance != null) {
            new LenientCopyTool().copyToMock(spiedInstance, mock);
        }

        return mock;
    }

[4]通过MockHandlerFactory创建mock的处理器对象,用于计算mock对象操作的结果

MockHandlerFactory.java

    public InternalMockHandler create(MockCreationSettings settings) {
        // 核心处理器
        InternalMockHandler handler = new MockHandlerImpl(settings);
        // 处理null和基本数据类型(静态代理)
        InternalMockHandler nullResultGuardian = new NullResultGuardian(handler);
        // 通知监听者
        InternalMockHandler notifier = new InvocationNotifierHandler(nullResultGuardian, settings);

        return notifier;
    }
	

由于处理器功能比较复杂,在后面会专门介绍

[5]这里的mockMaker是全局变量,让我们看看这个变量是如何获得的

MockUtil.java
// 通过插件获取该对象
MockMaker mockMaker = Plugins.getMockMaker();

Plugins.java
public static MockMaker getMockMaker() {
    // 再访问插件注册器
    return registry.getMockMaker();
}


[6]
PluginRegistry.java
    private final PluginSwitch pluginSwitch
            = new PluginLoader(new DefaultPluginSwitch()).loadPlugin(PluginSwitch.class, DefaultPluginSwitch.class.getName());
			
			
    private final MockMaker mockMaker
            = new PluginLoader(pluginSwitch).loadPlugin(MockMaker.class, "org.mockito.internal.creation.cglib.CglibMockMaker");

    MockMaker getMockMaker() {
        return mockMaker;
    }

[6] 由于PluginRegistry是一个独立的模块,这里直接介绍完:
(1)首先介绍PluginSwitch,它只有一个方法isEnabled(String pluginClassName),表示当前插件是否可用
(2)上面的代码在获取PluginSwitch对象时使用了PluginLoader.loadPlugin方法,来看一下这个方法在干嘛

 PluginLoader.java

 <T> T loadPlugin(Class<T> pluginType, String defaultPluginClassName) {
        // 加载插件(核心方法)
        T plugin = loadImpl(pluginType);
        if (plugin != null) {
            return plugin;
        }

        try {
            // 如果插件没有找到就使用默认的插件类
            return pluginType.cast(Class.forName(defaultPluginClassName).newInstance());
        } catch (Exception e) {
            throw new MockitoException("Internal problem occurred, please report it. " +
                    "Mockito is unable to load the default implementation of class that is a part of Mockito distribution. " +
                    "Failed to load " + pluginType, e);
        }
    }
	
<T> T loadImpl(Class<T> service) {
        // 获取有效的类加载器
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if (loader == null) {
            loader = ClassLoader.getSystemClassLoader();
        }
        Enumeration<URL> resources;
        try {
		    // 获取classpath下的mockito-extensions/插件名的文件
            resources = loader.getResources("mockito-extensions/" + service.getName());
        } catch (IOException e) {
            throw new MockitoException("Failed to load " + service, e);
        }

        try {
		    // 简述过程:根据读取插件文件列表中的文件内容(文件中应该是插件的类全名),通过pluginSwitch控制某些插件不可用
            String foundPluginClass = new PluginFinder(pluginSwitch).findPluginClass(Iterables.toIterable(resources));
            if (foundPluginClass != null) {
			    // 创建插件实例
                Class<?> pluginClass = loader.loadClass(foundPluginClass);
                Object plugin = pluginClass.newInstance();
                return service.cast(plugin);
            }
            return null;
        } catch (Exception e) {
            throw new MockitoConfigurationException(
                    "Failed to load " + service + " implementation declared in " + resources, e);
        }
    }

因为自带的代码中在classpath下不存在mockito-extensions目录,所以都是使用默认的插件类。即:PluginSwitch使用的插件类是DefaultPluginSwitch(所有的插件都是可用的),MockMaker使用的是CglibMockMaker(使用cglib创建mock对象,但是要求该对象不能是final修饰和基本数据类型)

说完插件,现在又回到我们的重点:[5]

MockUtil.java
    T mock = mockMaker.createMock(settings, mockHandler);

从上面对插件的介绍可以得知,mockMaker是org.mockito.internal.creation.cglib.CglibMockMaker的实例,所以我们要看一下CglibMockMaker.createMock方法是如何实现的

CglibMockMaker.java

    public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) {
	     // 校验并强转为InternalMockHandler对象,实际根据 new MockHandlerFactory().create(settings)创建handler实例的方式可以得知,handler是InvocationNotifierHandler的实例
        InternalMockHandler mockitoHandler = cast(handler);
		// 设置jvm序列化可用
        new AcrossJVMSerializationFeature().enableSerializationAcrossJVM(settings);
        // [7]
        return new ClassImposterizer(new InstantiatorProvider().getInstantiator(settings)).imposterise(
                // MethodInterceptorFilter会改变原有方法的行为
                new MethodInterceptorFilter(mockitoHandler, settings), settings.getTypeToMock(), settings.getExtraInterfaces());
    }

[7]new InstantiatorProvider().getInstantiator(settings)是用来获取创建实例的工具类对象

    public Instantiator getInstantiator(MockCreationSettings settings) {
        if (settings.isUsingConstructor()) {
		// 如果配置中指定需要使用构造器创建实例,就返回ConstructorInstantiator对象
            return new ConstructorInstantiator(settings.getOuterClassInstance());
        } else {
            return INSTANCE;
        }
    }

[7]new ClassImposterizer(new InstantiatorProvider().getInstantiator(settings))解读

CglibMockMaker.java

    /**
     * 如果settings指定需要使用构造器,就使用ConstructorInstantiator实例化
     * @param settings mock配置对象
     * @return
     */
    public Instantiator getInstantiator(MockCreationSettings settings) {
        if (settings.isUsingConstructor()) {
		    // 如果使用的是构造器创建实例,settings.getOuterClassInstance()对应的是构造器实参列表
            return new ConstructorInstantiator(settings.getOuterClassInstance());
        } else {
		    //Instantiator INSTANCE = new ObjenesisInstantiator(); 注意:Objenesis可以绕开对象实例构造器实例化对象
            return INSTANCE;
        }
    }

imposterise方法介绍:


ClassImposterizer.java


  /**
     * 创建代理class对象
     * @param interceptor 方法拦截器,修改原有方法的处理逻辑
     * @param mockedType mock对象继承类或者实现的接口
	 * @param ancillaryTypes mock对象需要额外实现的接口列表
     * @return
     */
 public <T> T imposterise(final MethodInterceptor interceptor, Class<T> mockedType, Class<?>... ancillaryTypes) {
        Class<Factory> proxyClass = null;
        Object proxyInstance = null;
        try {
		    // 设置构造器可访问权限
            setConstructorsAccessible(mockedType, true);
            // [8]
            proxyClass = createProxyClass(mockedType, ancillaryTypes);
			// [9]
            proxyInstance = createProxy(proxyClass, interceptor);
            return mockedType.cast(proxyInstance);
        } catch (ClassCastException cce) {
            throw new MockitoException(join(
                "ClassCastException occurred while creating the mockito proxy :",
                "  class to mock : " + describeClass(mockedType),
                "  created class : " + describeClass(proxyClass),
                "  proxy instance class : " + describeClass(proxyInstance),
                "  instance creation by : " + instantiator.getClass().getSimpleName(),
                "",
                "You might experience classloading issues, disabling the Objenesis cache *might* help (see MockitoConfiguration)"
            ), cce);
        } finally {
            setConstructorsAccessible(mockedType, false);
        }
    }

	

[8]代理的class对象

	
  /**
     * 创建代理class对象
     * @param mockedType mock对象继承类或者实现的接口
	 * @param interfaces mock对象需要额外实现的接口列表
     * @return
     */
    public Class<Factory> createProxyClass(Class<?> mockedType, Class<?>... interfaces) {
        if (mockedType == Object.class) {
		    // 定义一个特殊类(没有任何字段和方法,相当于Object但是类型更明确)
            mockedType = ClassWithSuperclassToWorkAroundCglibBug.class;
        }
        
        Enhancer enhancer = new Enhancer() {
            @Override
            @SuppressWarnings("unchecked")
            protected void filterConstructors(Class sc, List constructors) {
                // Don't filter
            }
        };
        // 所有的mock类型(mock类型和接口类型)
        Class<?>[] allMockedTypes = prepend(mockedType, interfaces);
        // 设置类加载器
		enhancer.setClassLoader(SearchingClassLoader.combineLoadersOf(allMockedTypes));
        enhancer.setUseFactory(true);
        if (mockedType.isInterface()) {
            // mock类型是接口
            enhancer.setSuperclass(Object.class);
			// 设置所有需要实现的接口列表
            enhancer.setInterfaces(allMockedTypes);
        } else {
		    // 如果mock是类
            enhancer.setSuperclass(mockedType);
            enhancer.setInterfaces(interfaces);
        }
        // 设置方法拦截器
        enhancer.setCallbackTypes(new Class[]{MethodInterceptor.class, NoOp.class});
		// 设置方法过滤(不拦截桥接方法)
        enhancer.setCallbackFilter(IGNORE_BRIDGE_METHODS);
		// 设置命名策略,默认的是:被代理class name + "$$" + 使用cglib处理的class name + "ByCGLIB" + "$$" + key的hashcode,示例:FastSource$$FastClassByCGLIB$$e1a36bab.class
        if (mockedType.getSigners() != null) {
            // 类标识存在
            enhancer.setNamingPolicy(NAMING_POLICY_THAT_ALLOWS_IMPOSTERISATION_OF_CLASSES_IN_SIGNED_PACKAGES);
        } else {
            enhancer.setNamingPolicy(MockitoNamingPolicy.INSTANCE);
        }

        enhancer.setSerialVersionUID(42L);
        
        try {
		    // 创建实例
            return enhancer.createClass(); 
        } catch (CodeGenerationException e) {
            if (Modifier.isPrivate(mockedType.getModifiers())) {
                throw new MockitoException("\n"
                        + "Mockito cannot mock this class: " + mockedType 
                        + ".\n"
                        + "Most likely it is a private class that is not visible by Mockito");
            }
            throw new MockitoException("\n"
                    + "Mockito cannot mock this class: " + mockedType 
                    + "\n" 
                    + "Mockito can only mock visible & non-final classes."
                    + "\n" 
                    + "If you're not sure why you're getting this error, please report to the mailing list.", e);
        }
    }
	
	
    /**
     * 合并多个class对象
     * @param first
     * @param rest
     * @return
     */
    private Class<?>[] prepend(Class<?> first, Class<?>... rest) {
        Class<?>[] all = new Class<?>[rest.length+1];
        all[0] = first;
        System.arraycopy(rest, 0, all, 1, rest.length);
        return all;
    }

[9]创建代理实例


  /**
     * 创建代理对象
     * @param proxyClass 代理类的class对象
     * @param interceptor 方法拦截器
     * @return
     */
    private Object createProxy(Class<Factory> proxyClass, final MethodInterceptor interceptor) {
        Factory proxy;
        try {
            // 使用实例化器创建代理对象(支持构造器和Objenesis创建实例)
            proxy = instantiator.newInstance(proxyClass);
        } catch (InstantationException e) {
            throw new MockitoException("Unable to create mock instance of type '" + proxyClass.getSuperclass().getSimpleName() + "'", e);
        }
        // 设置拦截
        proxy.setCallbacks(new Callback[] {interceptor, SerializableNoOp.SERIALIZABLE_INSTANCE });
        return proxy;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值