简单的说,代理模式是在目标对象和访问对象之间增加了一层代理对象,所有的访问对象通过代理对象来实现对目标对象的调用。
代理对象和目标对象实现同一个接口,由代理对象来调用目标对象,对于外部来说,代理对象就可以替代目标对象被调用。通过这种方式,代理对象中可以在正常的访问中增加额外的逻辑,比如缓存、权限控制、日志记录等。
但是这种静态代理的模式需要增加额外的代理类的实现,Java 5开始引入了动态代理机制,实现了在运行时动态地创建出代理对象,这其实是一种方法调用的拦截,AOP就是利用了这种模式。
动态代理的使用例子
package com.dynamic.jdk;
/**
* 目标类的接口定义
* <p/>
* Created by Vincent Tse on 12/2/15.
*/
public interface MyInterface {
void doSomething();
}
package com.dynamic.jdk;
/**
* 目标类的具体实现
* <p/>
* Created by Vincent Tse on 12/2/15.
*/
public class MyInterfaceImpl implements MyInterface {
@Override
public void doSomething() {
System.out.println("here is my real operation!");
}
}
package com.dynamic.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 自定义的InvocationHandler
* 封装具体的调用过程
* <p/>
* Created by Vincent Tse on 12/2/15.
*/
public class MyInvocationHandler implements InvocationHandler {
//target是真正执行方法的目标对象
private Object target;
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
/**
* 代理对象调用的方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before target's operation!");
Object result = method.invoke(target, args);
System.out.println("after target's operation");
return result;
}
}
package com.dynamic.jdk;
import java.lang.reflect.Proxy;
/**
* 测试类
* <p/>
* Created by Vincent on 12/2/15.
*/
public class DynamicTest {
public static void main(String[] args) {
//生成目标对象
MyInterface myInterface = new MyInterfaceImpl();
//实例化invocationHandler对象,传入目标对象作为target
MyInvocationHandler invocationHandler = new MyInvocationHandler(myInterface);
//调用Proxy的方法生成代理对象
MyInterface proxy = (MyInterface)Proxy.newProxyInstance(myInterface.getClass().getClassLoader(),
new Class[]{MyInterface.class}, invocationHandler);
//调用代理对象的方法
proxy.doSomething();
}
}
输出结果:
before target's operation!
here is my real operation!
after target's operation!
使用起来很简单,接下来看源码分析其中的原理
从Proxy的newProxyInstance()方法开始,这个方法就是用来生成代理对象的,需要传入类加载器、实现的接口以及一个InvocationHandler对象。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
//通过传入的类加载器和实现接口生成代理类
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//反射获取代理类的构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//反射生成实例,将invocationHandler传入,之后调用invoke方法就靠它了
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);
}
}
getProxyClass0()方法就是用来生成代理类的,首先检查实现接口数量,大于65535就抛异常,感觉应该不会有实现那么多接口的类吧。
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//从一个Cache中获取代理类,如果没有就重新生成
return proxyClassCache.get(loader, interfaces);
}
proxyClassCache是一个静态的WeakCache,定义在Proxy类里。
WeakCache里有两个factory,一个是subKeyFactory, 是一个映射函数(key, parameter)->sub-key, 另一个是valueFactory,是一个映射函数(key, parameter)->value。WeakCache的get方法需要两个参数,一个是key,另一个是parameter。
具体WeakCache的用法与原理这里不再赘述,请参考源码。
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
这里传入的KeyFactory和ProxyClassFactory是Proxy类中定义的静态类,分别对应了WeakCache中的subKeyFactory和valueFactory,都实现了BiFunction接口,并实现了apply()方法。ProxyClassFactory的apply()方法里完成的就是生成代理类的逻辑,最关键的是
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
上面的方法用来生成代理类的字节码,这个代理类里会有接口的实现方法,在实现的方法中会调用InvocationHandler的invoke()方法,有兴趣的可以将生成的字节码写到本地,用反编译工具打开看一下。
那么ProxyClassFactory的apply()方法是在什么时候被调用的呢,回到WeakCache的get()方法
//生成subkey来获取对应的supplier
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
//一直循环,直到从supplier中获取到value为止
//如果没有supplier就生成factory并加入到缓存中(源码说这是一个install的过程)
while (true) {
if (supplier != null) {
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
//Factory是内部类,实现了Supplier接口,实现了get()方法
//实际上在get()方法中调用了valueFactory(也就是ProxyClassFactory)的apply()方法
//可以debug进去看
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
好辛苦,终于生成代理类了,回到newProxyInstance方法,有了代理类的Class对象,就可以通过反射生成实例(调用的是带InvocationHandler参数的构造函数),生成实例之后就可以用代理对象了。