代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
抽象角色Subject:通过接口或抽象类声明真实角色实现的业务方法。
代理角色Proxy:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色RealSubject:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用
静态代理是由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
根据上面代理模式的类图,可以很简单的写出静态代理的例子。
代理类在程序运行时创建的代理方式被成为动态代理。动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。是因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。
JDK提供了Proxy类的newProxyInstance方法,可以创建一个动态代理对象
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class>[] intfs = interfaces.clone();
// Android-changed: sm is always null
// final SecurityManager sm = System.getSecurityManager();
// if (sm != null) {
// checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
// }
/*
* Look up or generate the designated proxy class.
*/
Class> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
// Android-changed: sm is always null
// if (sm != null) {
// checkNewProxyPermission(Reflection.getCallerClass(), cl);
// }
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
// Android-changed: Removed AccessController.doPrivileged
cons.setAccessible(true);
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
private static Class> getProxyClass0(ClassLoader var0, Class... var1) {
if (var1.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
} else {
return (Class)proxyClassCache.get(var0, var1);
}
}
通过 getProxyClass0方法获取到了代理类
private static final WeakCache
ProxyClassFactory动态生成了代理类,ProxyClassFactory调用了ProxyGenerator动态生成了代理类的字节码。
JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
如何对类进行代理呢?可以使用CGLIB
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
JDK和Cglib对比
JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。
mockito最开始使用了Cglib创建动态代理,后来修改为使用bytebuddy。
//Mockito.mock方法
public static T mock(Class classToMock, MockSettings mockSettings) {
return MOCKITO_CORE.mock(classToMock, mockSettings);
}
//MOCKITO_CORE.mock方法
public T mock(Class typeToMock, MockSettings settings) {
if (!MockSettingsImpl.class.isInstance(settings)) {
throw new IllegalArgumentException("Unexpected implementation of '" + settings.getClass().getCanonicalName() + "'\n" + "At the moment, you cannot provide your own implementations of that class.");
}
MockSettingsImpl impl = MockSettingsImpl.class.cast(settings);
MockCreationSettings creationSettings = impl.build(typeToMock);
T mock = createMock(creationSettings);
mockingProgress().mockingStarted(mock, creationSettings);
return mock;
}
//MockUtil createMock方法
public static T createMock(MockCreationSettings settings) {
MockHandler mockHandler = createMockHandler(settings);
T mock = mockMaker.createMock(settings, mockHandler);
Object spiedInstance = settings.getSpiedInstance();
if (spiedInstance != null) {
new LenientCopyTool().copyToMock(spiedInstance, mock);
}
return mock;
}
//SubclassByteBuddyMockMaker createMock方法
public T createMock(MockCreationSettings settings, MockHandler handler) {
Class extends T> mockedProxyType = createMockType(settings);
Instantiator instantiator = Plugins.getInstantiatorProvider().getInstantiator(settings);
T mockInstance = null;
try {
mockInstance = instantiator.newInstance(mockedProxyType);
MockAccess mockAccess = (MockAccess) mockInstance;
mockAccess.setMockitoInterceptor(new MockMethodInterceptor(handler, settings));
return ensureMockIsAssignableToMockedType(settings, mockInstance);
} catch (ClassCastException cce) {
throw new MockitoException(join(
"ClassCastException occurred while creating the mockito mock :",
" class to mock : " + describeClass(settings.getTypeToMock()),
" created class : " + describeClass(mockedProxyType),
" proxy instance class : " + describeClass(mockInstance),
" instance creation by : " + instantiator.getClass().getSimpleName(),
"",
"You might experience classloading issues, please ask the mockito mailing-list.",
""
), cce);
} catch (org.mockito.creation.instance.InstantiationException e) {
throw new MockitoException("Unable to create mock instance of type '" + mockedProxyType.getSuperclass().getSimpleName() + "'", e);
}
}
//SubclassByteBuddyMockMaker createMockType方法
public Class extends T> createMockType(MockCreationSettings settings) {
try {
return cachingMockBytecodeGenerator.mockClass(MockFeatures.withMockFeatures(
settings.getTypeToMock(),
settings.getExtraInterfaces(),
settings.getSerializableMode(),
settings.isStripAnnotations()
));
} catch (Exception bytecodeGenerationFailed) {
throw prettifyFailure(settings, bytecodeGenerationFailed);
}
}
//SubclassBytecodeGenerator mockClass方法
public Class extends T> mockClass(MockFeatures features) {
String name = nameFor(features.mockedType);
DynamicType.Builder builder =
byteBuddy.subclass(features.mockedType)
.name(name)
.ignoreAlso(isGroovyMethod())
.annotateType(features.stripAnnotations
? new Annotation[0]
: features.mockedType.getAnnotations())
.implement(new ArrayList(features.interfaces))
.method(matcher)
.intercept(dispatcher)
.transform(withModifiers(SynchronizationState.PLAIN))
.attribute(features.stripAnnotations
? MethodAttributeAppender.NoOp.INSTANCE
: INCLUDING_RECEIVER)
.method(isHashCode())
.intercept(hashCode)
.method(isEquals())
.intercept(equals)
.serialVersionUid(42L)
.defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE)
.implement(MockAccess.class)
.intercept(FieldAccessor.ofBeanProperty());
if (features.serializableMode == SerializableMode.ACROSS_CLASSLOADERS) {
builder = builder.implement(CrossClassLoaderSerializableMock.class)
.intercept(writeReplace);
}
if (readReplace != null) {
builder = builder.defineMethod("readObject", void.class, Visibility.PRIVATE)
.withParameters(ObjectInputStream.class)
.throwing(ClassNotFoundException.class, IOException.class)
.intercept(readReplace);
}
ClassLoader classLoader = new MultipleParentClassLoader.Builder()
.append(features.mockedType)
.append(features.interfaces)
.append(currentThread().getContextClassLoader())
.append(MockAccess.class, DispatcherDefaultingToRealMethod.class)
.append(MockMethodInterceptor.class,
MockMethodInterceptor.ForHashCode.class,
MockMethodInterceptor.ForEquals.class).build(MockMethodInterceptor.class.getClassLoader());
if (classLoader != features.mockedType.getClassLoader()) {
assertVisibility(features.mockedType);
for (Class> iFace : features.interfaces) {
assertVisibility(iFace);
}
builder = builder.ignoreAlso(isPackagePrivate()
.or(returns(isPackagePrivate()))
.or(hasParameters(whereAny(hasType(isPackagePrivate())))));
}
return builder.make()
.load(classLoader, loader.resolveStrategy(features.mockedType, classLoader, name.startsWith(CODEGEN_PACKAGE)))
.getLoaded();
}
最终mockito 在SubclassBytecodeGenerator类中使用bytebuddy 动态创建了一个代理类,bytebuddy提供了一个API用于动态生成任意的Java类。
动态代理使用了继承,所以不能代理final类。
mockito2.0开始支持代理final类,它是如何实现的呢?
2.0引入新的插件InlineByteBuddyMockMaker,在InlineBytecodeGenerator中进行字节码转换,原理是使用JAVA instrumentation动态修改类的行为(注意这里不是Android的instrumentation)。
Android中不能使用 inline插件,因为JAVA的 java.lang.instrument Android中是不可见的,会抛出NoClassDefFoundError异常