动态代理是使用非常广泛的技术,诸如大名鼎鼎的spring、mybatis等框架都大量使用动态代理。动态代理区别于静态代理的地方在于:静态代理需要为每一个被代理类都创建一个代理类,在编译期代理类就已经生成,而动态代理则是在程序运行期动态地生成代理类,所有被代理对象的执行逻辑都被转移到InvocationHandler对象的invoke方法,在invoke方法里通过反射来调用被代理的对象方法,当然也可以执行其它的逻辑。动态代理的一个显而易见的好处是:不用为每个被代理类都手动创建一个代理类。
按照惯例,先谈使用再讲原理。举个例子先。
场景:七夕临近,公司交友社团本着消灭单身狗的美好愿景,为闷骚的程序猿(媛)们开通了月老服务,任何有心仪目标但是又羞于开口的单身程序狗都可以委托“月老”来约心中的男神女神出来。
Suitor(追求者)接口
public interface Suitor {
void sayHi(Beauty beauty);
}
Programmer(程序猿)
public class Programmer implements Suitor {
@Override
public void sayHi(Beauty beauty) {
System.out.println("Hello, " + beauty.getName() + "! Would you like to have dinner with me tonight?");
}
}
Beauty(MM)
public class Beauty {
private String name;
public Beauty(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
处理邀请MM动作的InvocationHandler
public class SuitorInvocationHandler implements InvocationHandler {
Suitor suitor;
public SuitorInvocationHandler(Suitor suitor) {
this.suitor = suitor;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(suitor, args);
}
}
测试,创建代理对象并对MM发出邀请
public class DynamicProxyTest {
@Test
public void test() {
Beauty beauty = new Beauty("MM");
InvocationHandler handler = new SuitorInvocationHandler(new Programmer());
Suitor suitor = (Suitor) Proxy.newProxyInstance(Suitor.class.getClassLoader(), new Class<?>[]{Suitor.class}, handler);
suitor.sayHi(beauty);
}
}
结果
Hello, MM! Would you like to have dinner with me tonight?
可见,代理对象成功地激发了被代理对象想执行的业务逻辑。
废话不多说,看看代理对象到底是如何生成的,业务逻辑又是如何转嫁到InvocationHandler上的。
Proxy.newProxyInstance中调用生成代理类的逻辑 Class<?> cl = getProxyClass0(loader, intfs);
@CallerSensitive
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);
}
/*
* Look up or generate the designated proxy class.
* 生成代理类
*/
Class<?> cl = getProxyClass0(loader,