静态代理有一个问题就是,如果被代理的目标类非常多,那我们就要生成非常多的代理类,比如我们上一节的例子中,我要记录性能的类,如果有100+个,那我就要再写100多个代理类,这显然是不合理的。
这是动态代理就登场了。
动态代理就是不用事先为每一个被代理的目标类,一一生成代理类,而是在运行时,按照需要动态生成代理类,来完成代理工作。
Java本身就实现了动态代理功能,其原理是基于反射实现的。
我们来看一下上一节的静态代理,如何演变为动态代理。
1、定义抽象用户类
package com.my.study.design.proxy.dynamic;
/**
* www.itzhimei.com
*/
public interface IUser {
void business() throws InterruptedException;
}
2、定义具体用户类,实现抽象用户类
package com.my.study.design.proxy.dynamic;
/**
* www.itzhimei.com
*/
public class User implements IUser {
@Override
public void business() throws InterruptedException {
System.out.println("用户类输出:执行业务方法计算中....");
Thread.sleep(500L);
System.out.println("用户类输出:执行业务方法计算完成");
}
}
3、定义动态代理的业务处理类,也就是代理的处理逻辑,要写在这里
package com.my.study.design.proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* www.itzhimei.com
*/
public class DynamicProxy implements InvocationHandler {
private Object realObject;
public DynamicProxy(Object realObject) {
this.realObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理输出:前置业务方法计算中....");
method.invoke(realObject,args);
System.out.println("动态代理输出:附加业务方法计算中....");
return null;
}
}
Java的动态代理API要求动态代理的代理处理逻辑,要实现InvocationHandler接口,覆写invoke()方法。这里就相当于静态代理中我们分别实现了login方法和business()方法。
4、测试
import java.lang.reflect.Proxy;
/**
* www.itzhimei.com
*/
public class Client {
public static void main(String[] args) throws InterruptedException {
User user = new User();
DynamicProxy handler = new DynamicProxy(user);
IUser u = (IUser)Proxy.newProxyInstance(user.getClass().getClassLoader(),user.getClass().getInterfaces(),handler);
u.business();
}
}
这里的一个重要方法就是Proxy.newProxyInstance(),这是生成动态代理的类和方法。
5、输出
动态代理输出:前置业务方法计算中....
用户类输出:执行业务方法计算中....
用户类输出:执行业务方法计算完成
动态代理输出:附加业务方法计算中....
我们看到,动态代理的输出日志和handle中定义的invoke是一致的,在实际的业务方法之前和之后执行。