前言
插件化开发所涉及到的技术点非常多, 比如程序的启动流程, 四大组件启动流程, ClassLoader 原理, 上下文 Context,AMS 原理, 反射, 代理等. 本篇主要简单介绍代理模式(实际上只是一篇学习笔记), 为后面介绍插件化实现做知识铺垫.
一, 定义
定义: 为其他对象提供一种代理, 以控制对这个对象的访问, 这种形式称为代理模式.(看起来挺抽象的, 不好理解, 能理解下面的解释就够了)
代理模式也叫委托模式, 是结构性设计模式的一种. 在现实生活中, 我们用到类似代理模式的场景非常多, 比如买房者找房屋中介买房, 受害者委托律师打官司, 老板安排助理采购等. 这些场景有一个共同特点: 真正想做某件事的人 , 因为行业壁垒等各种原因自己不容易完成, 于是转而找其他专业人士来替自己完成这个意愿. 以老板安排助理采购电脑设备为例: 老板 (即委托者) 是真是需要购买电脑设备的人, 但由于缺乏对电脑设备的了解, 于是委派助理 (即代理) 来完成自己的这次采购意愿.
二, 角色及结构
在代理模式中, 包含了如下的角色:
Subject: 抽象主题类, 声明真实主题与代理的共同接口方法. 也就是定义一个接口, 定义老板和助理的这次行为: 采购!
RealSubject: 真实主题类, 定义了代理所表示的集体对象, 客户端通过代理类间接调用真实主题类的方法. 即老板, 真正需要采购的人.
Proxy: 代理类, 持有对真实主题类的引用, 在其所实现的接口方法中调用真实主题类中相应的接口方法执行. 即助理, 以老板的名义去采购.
Client: 客户端类. 也就是一段逻辑代码, 将上述角色组织起来, 完成这次采购行为.
类结构图如下:
三, 代码实现
从编码的角度来说, 代理模式分为静态代理和动态代理, 可以结合下面的例子来理解.(1)静态代理, 在代码运行前代理类的 class 文件就已经存在了, 结合下面的代码直观的理解就是, 代理类 Assistant 类是写死的, 在运行前这个编译类 Assistant.class 就存在了.(2)动态代理, 则是在代码运行时才会通过反射来动态地生成代理类对象, 并确定到底来代理谁. 也就是说, 我们在编码阶段并不会定义出这个代理类, 而是在运行的时候动态生成. 从下面的代码实现中, 我们发现, 动态代理实现时, 并没有出现 Assistant 这个类.
下面我们来用代码实现静态代理和动态代理.
1, 静态代理
- //Subject: 抽象主题类, 定义了老板和助理的这次行为
- public interface IShop {
- void buy();
- }
- //RealSubject: 真实主体类. 实现了抽象主题接口
- public class Boss implements IShop {
- @Override
- public void buy() {
- System.out.println("I am boss,I buy buy buy");
- }
- }
- //Proxy: 代理类. 以组合的方式持有了对真实主题类 Boss 的引用, 也实现了抽象主题接口. 在实现的 buy 方法中, 调用了真实主题 Boss 的对应方法.
- public class Assistant implements IShop {
- private IShop mBoss;
- Assistant(IShop shoper) {
- mBoss = shoper;
- }
- @Override
- public void buy() {
- mBoss.buy();
- }
- }
- //Client: 客户端类
- public class ProxyDemo {
- public static void main(String[] args) {
- IShop boss = new Boss();
- IShop assitant = new Assistant(boss);
- assitant.buy();
- }
- }
运行结果
I am boss,I buy buy buy
这里我们可以看到, Client 类中调用的是代理 Assistant 的 buy 方法, 而实际完成的是委托者 Boss 的 buy 方法, 从而实现了这次代理行为.
2, 动态代理
- public interface IShop {
- void buy();
- }
- public class Boss implements IShop {
- @Override
- public void buy() {
- System.out.println("I am boss,I buy buy buy");
- }
- }
- //Java 提供了动态的代理接口 InvocationHandler, 实现该接口需要重写 invoke 方法.
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- public class DynamicProxy implements InvocationHandler {
- private Object mObject;
- DynamicProxy(Object object) {
- mObject = object;
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
- System.out.println("invoke methodName=" + method.getName());
- method.invoke(mObject, objects);
- return null;
- }
- }
- //Client
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- public class Client {
- public static void main(String[] args) {
- // 创建 boss 类
- IShop boss = new Boss();
- // 创建动态代理
- InvocationHandler proxyHandler = new DynamicProxy(boss);
- ClassLoader classLoader = boss.getClass().getClassLoader();
- // 动态创建代理类
- IShop assitant = (IShop) Proxy.newProxyInstance(classLoader, new Class[]{IShop.class}, proxyHandler);
- assitant.buy();
- }
- }
运行结果
- invoke methodName=buy
- I am boss,I buy buy buy
在动态代理类 DynamicProxy 中, 声明了一个 Object 的引用, 该应用指向被代理类对象 (该实例中指向的就是 Boss 类对象), 我们调用被代理类对象(Boss 对象) 的具体方法 (该例子中指 buy 方法) 会在 invoke 方法中执行. 在 Client 类中的 Proxy.newProxyInstance()来生成动态代理类对象 assistant, 而调用 assistant.buy()方法时会调用 DynamicProxy 类中的 invoke 方法, 这样就间接地调用了 Boss 类中的 buy()方法, 从而实现了动态代理.
四, 静态代理和动态代理对比
说到使用动态代理的好处, 可能得一大篇文章才说得清楚, 在这里我只想提一点, 就是动态代理下, 直到运行时才会生成代理类, 当代理场景比较多时, 可以节约很多不必要的浪费. 这里我们比较一下, 有多个代理场景时, 静态代理和动态代理的表现.
1, 静态代理实现多个代理场景
- public interface IShop {
- void buy();
- }
- public class Boss implements IShop {
- @Override
- public void buy() {
- System.out.println("I am boss,I buy buy buy");
- }
- }
- public class Assistant implements IShop {
- private IShop mBoss;
- Assistant(IShop shoper) {
- mBoss = shoper;
- }
- @Override
- public void buy() {
- mBoss.buy();
- }
- }
- public interface IDrive {
- void drive();
- }
- public class Leader implements IDrive {
- @Override
- public void drive() {
- System.out.println("I am leader,I drive drive drive");
- }
- }
- public class Driver implements IDrive {
- private IDrive mLeader;
- Driver(IDrive driver) {
- mLeader = driver;
- }
- @Override
- public void drive() {
- mLeader.drive();
- }
- }
- public class ProxyDemo {
- public static void main(String[] args) {
- IShop boss = new Boss();
- IShop assitant = new Assistant(boss);
- assitant.buy();
- IDrive leader = new Leader();
- IDrive driver = new Driver(leader);
- driver.drive();
- }
- }
运行结果
- I am boss, I buy buy buy
- I am leader,I drive drive drive
如上代码实际上就是两个代理场景的叠加, 增加一个场景, 代码量增加一倍.
2, 动态代理实现多个代理场景
- public interface IShop {
- void buy();
- }
- public class Boss implements IShop {
- @Override
- public void buy() {
- System.out.println("I am boss,I buy buy buy");
- }
- }
- public interface IDrive {
- void drive();
- }
- public class Leader implements IDrive {
- @Override
- public void drive() {
- System.out.println("I am leader,I drive drive drive");
- }
- }
- // 动态代理类
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- public class DynamicProxy implements InvocationHandler {
- private Object mObject;
- DynamicProxy(Object object) {
- mObject = object;
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
- System.out.println("invoke methodName=" + method.getName());
- method.invoke(mObject, objects);
- return null;
- }
- }
- //Client
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- public class Client {
- public static void main(String[] args) {
- IShop boss = new Boss();
- InvocationHandler proxyHandler = new DynamicProxy(boss);
- ClassLoader classLoader = boss.getClass().getClassLoader();
- IShop assitant = (IShop) Proxy.newProxyInstance(classLoader, new Class[]{IShop.class}, proxyHandler);
- assitant.buy();
- }
- }
运行结果
- invoke methodName=buy
- I am boss, I buy buy buy
- invoke methodName=drive
- I am leader,I drive drive drive
由于不需要单独实现代理类, 多个代理场景下实际上就节约了很多的代码量.
结语
代理模式作为设计模式中的一种, 使用比较广泛, 内容非常多, 笔者知识有限, 暂时先介绍这么多, 希望能帮助初学者能够掌握代理模式的基本知识和使用.
来源: https://www.cnblogs.com/andy-songwei/p/13382222.html