静态代理
代理从字面意思来看就是,替代XX去做某事,在我们的程序中,一般替代实际对象去进行操作,扮演着中间人的角色:
客户端 –> 业务类
客户端 –> 代理 –>业务类(代理)
代理接口
interface Operation{
void download();
}
实际对象(业务类)
class RealObject implements Operation{
@Override
public void download() {
//进行逻辑操作
}
}
代理类
class ProxyObject implements Operation{
private Operation operation;
public ProxyObject(Operation operation) {
this.operation = operation;
}
@Override
public void download() {
operation.download();//通过代理来调用实际对象的方法
}
}
主类
public class TestProxy {
public static void main(String[] args) {
Operation operation = new ProxyObject(new RealObject());//把实际对象传入代理
operation.download();
}
}
代理的优点:业务类只需要关注业务本身,保证了代码的重用性。
代理的缺点:一个真实角色只能对应一个代理角色,要是真实角色多了,代理也随着增多,会导致类的急剧膨胀。
场景描述
假设有这么一个类:(在此简化代码,但实际代码非常复杂)
class RealObject implements Operation{
@Override
public void download() {
//我要测量这个方法所在的线程和花费的时间等,这个操作代码量可能为50行
}
}
我需要做一些对这个类进行一些跟踪的操作或者测量一下这个类的内存开销,比如我想打印一下这个类的某个方法所在的线程和花费时间,这个类非常复杂,难道我要把这些操作整合到类中吗?显然不明智!
明智的做法是:使用代理
动态代理
场景描述
假设有这样一个场景,你需要对某一个接口的方法进行扩展,这时你一般的选择是:
实现接口,并重写该方法!
但是我们知道,实现接口,则必须实现它所有的方法。方法少的接口倒还好,但是如果恰巧这个接口的方法有很多呢,例如List接口。
更好的选择是:
使用动态代理!
代理的使用场景:
如果对某个接口中的某个指定的方法的功能进行扩展,添加额外的用户逻辑,而不想实现接口里所有方法,可以使用(动态)代理模式,监听方法的执行!
下面是对一个List接口的isEmpty方法进行监听:
public class TestProxy {
@SuppressWarnings("unchecked")
private static List<Integer> createProxy() {
List<Integer> list = new ArrayList<>();
List<Integer> proxy = (List<Integer>) Proxy.newProxyInstance(
list.getClass().getClassLoader(),
new Class[]{List.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
String methodName = method.getName();
if("isEmpty".equals(methodName)){//捕获我们需要监听的方法
System.out.println("你调用了isEmpty方法");
}else{
result = invoke(proxy, method, args);//执行方法
}
return result;//返回执行方法的结果
}
});
return proxy;//返回代理
}
public static void main(String[] args) {
List<Integer> list = createProxy();
list.isEmpty();
}
}
结果为:
你调用了isEmpty方法
具体的步骤,注释里都很清楚,动态代理主要用到了Proxy的newProxyInstance(ClassLoader loader,Clas< ?>[] interfaces, InvocationHandler h)。
第一个参数:代理的类或接口的类加载器
第二个参数:代理的接口
第三个阐述:执行方法的Handler