代理模式的设计里面是限制对对象的直接访问,要想访问具体对象需要通过该对象的代理类去访问。
代理模式在很多地方是比较常见的,比如在 ARouter 内部,ARouter 的主要功能是通过其_ARouter 实现的,这里的 ARouter 就是_ARouter 的代理类。
/**
* Init, it must be call before used router.
*/
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
hasInit = _ARouter.init(application);
if (hasInit) {
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}
静态代理主要分为下面三个部分:
举个生活中我们使用代购替我们购买东西的例子。
创建购物抽象类:IShop
public interface IShop {
void shop();
}
创建具体实际的购物抽象类:(朋友替我们购物)
public class Friend implements IShop {
@Override
public void shop() {
System.out.println("朋友代替我们购物");
}
}
创建代理类:
public class ProxyShop implements IShop {
/**
* 实际购物对象
*/
private IShop realShop;
public ProxyShop(IShop realShop) {
this.realShop = realShop;
}
@Override
public void shop() {
System.out.println("委托朋友代购");
realShop.shop();
System.out.println("朋友把代购的物品交给我们");
}
}
创建测试类:
public class Main {
public static void main(String[] args) {
Friend friend = new Friend();
ProxyShop proxyShop = new ProxyShop(friend);
proxyShop.shop();
}
}
结果:
可以看到,朋友 friend 帮我们完成了购物动作,并且在代理类过程中,可以增加一些特殊的操作,在朋友帮我们代理购物的前后可以增加自定义操作。
上面讲了静态代理,我们需要预先把需要的情况都要列出来,然后编写代理代码,需要自己生成编写代理类。
而动态代理就可以在运行时通过 Proxy.newProxyInstance生成代理类,比如我们有了新的需求,让朋友帮我们交话费,这个时候,就需要创建交话费的抽象,然后创建充话费的代理,这是很麻烦的,下面通过动态代理模式实现。
下面仍然以购物为例
抽象购物:
public interface IShop {
void shop();
}
实际代理对象:Friend
public class Friend implements IShop {
@Override
public void shop() {
System.out.println("朋友代替我们购物");
}
}
动态代理:
public class DynamicProxyHandler implements InvocationHandler {
Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("委托朋友代购");
method.invoke(target,args);
System.out.println("朋友把代购的物品交给我们");
return null;
}
}
测试类:
public class Main {
public static void main(String[] args) {
Friend friend = new Friend();
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(friend);
IShop shop = (IShop) Proxy.newProxyInstance(Friend.class.getClassLoader(),Friend.class.getInterfaces(),dynamicProxyHandler);
shop.shop();
}
}
运行结果:
这就是动态代理的大致流程。
需要注意的是,上面 DynamicProxyHandler 里面的 invoke 里面的代码,是在执行代理接口的里面的方法的时候才会被执行到,而不是创建代理对象的时候执行,所以这里我们就可以额外的加入一些操作,比如在朋友把代购物品交给我们以后,我们还要向朋友付钱,那么就可以:
public class Main {
public static void main(String[] args) {
Friend friend = new Friend();
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(friend);
IShop shop = (IShop) Proxy.newProxyInstance(Friend.class.getClassLoader(),Friend.class.getInterfaces(),dynamicProxyHandler);
shop.shop();
System.out.println("我们向朋友付了商品的价钱");
}
}
结果:
可以看到,我们可以在方法具体执行的前后加入一些自定义逻辑,更加灵活,而且在没修改原来方法的情况下,可以增强代码功能。
通过上面的实例可以发现:
静态代理的代理类需要自己编写,而动态代理的代理类则是由运行时使用 newProxyInstance 动态生成,
同时不管是静态代理还是动态代理,都需要实现接口,本质上是面对接口编程的,能够增加现有代码的功能。
一些参考地址
轻松学,Java 中的代理模式及动态代理
从一道面试题开始说起 枚举、动态代理的原理