代理模式
    代理模式(Proxy Pattern)是Java中常用的一种设计模式。它属于【结构型】模式。
1、代理模式的核心思想：
    通过一个"代理对象"来代替"真实对象"，通过这种方式来控制对"真实对象"的访问。
    说人话，代理模式中代理，就是代理人，中介。
    代理模式就像中介、代购、经纪人。比如想租房，不需要直接找房东(真实对象)，
    而是找中介(代理对象)。中介会帮你联系房东，还能额外提供看房、签合同等等服务。
2、代理模式的核心特点：
    1、【代理类和真实类实现相同的接口，或者继承相同的父类】，保证代理对象和真实对象都能
    被统一使用，比如房东可以令你看房，中介也可以领你看房。
    2、【代理类持有真实对象的引用，可以直接调用真实对象的方法】，比如：中介手里有房东的联系方式，
    能够让房东最终交房。
    3、【代理类可以在调用真实对象的方法前后，添加额外的操作】。比如：中介要在签合同之前核实你的身份，
    签完合同要给中介费。
3、为什么需要代理模式？
代理模式的核心价值其实就是"控制访问"和"增强功能"：
    1、保护真实对象，比如限制只有管理员才能访问某一个敏感对象
    2、增强功能：在不修改真实对象的代码的前提下，添加一些功能，日志、权限校验、缓存等等功能
    3、远程访问：通过代理模式访问远端服务器里面的对象
4、代理模式的分类：
    静态代理
    动态代理
    两种代理方式核心逻辑是一样的， 但是实现的方式和使用的场景不一样。
--------------------------------------------------------------
静态代理(static proxy)
    静态代理就是在编译期就已经确定了代理类的代码， 需要我们手动写代理类。
实现步骤：租房
    1、定义接口(代表代理类和真实类有共同的行为)
    接口，其实就是代理类和真实类的"约定"，确保两个类能够被统一调用，
    创建一个Rent接口，包含租房方法。
    2、实现真实类---被代理的对象
    就是房东，是最终提供服务的对象，需要实现Rent接口
    3、实现代理类---中介
        |-实现Rent接口，保证行为和真实类一致。
        |-持有真实类的引用，可以通过构造传入。
        |-在调用真实类的方法的前后，添加额外的操作，比如中介的服务
静态代理的优缺点：
    优点：
        简单、直观、代码好理解、不需要依赖复杂的框架。
    缺点：
        当接口新增方法，代理类和真实类都需要修改。
        有多少个真实类，就得有多少个代理类

动态代理(Dynamic Proxy)
    动态代理是在程序运行时，通过反射动态生成代理类的代码，不需要我们手动编写代理类。
    解决了静态代理的每个真实类都要手写一个代理类的情况，适合批量处理多个类的场景。
    Java中常用的动态代理有两种：
        JDK动态代理，基于接口的。
        CGLIB动态代理，基于继承的。
1、JDK动态代理是Java官方提供的，java.lang.reflect包里，要求被代理的类必须要实现接口。
以给所有的方法添加日志，作为例子：
实现步骤：
    1、定义接口(比如：UserService)和真实类(实现类：UserServiceImpl)
    2、实现InvocationHandler接口，里面是代理逻辑
        JDK动态代理需要一个"调用处理程序|调用处理器"，实现InvocationHandler接口，
        用来定义代理类的额外操作，比如日志。
        InvocationHandler接口里只有一个抽象方法：
        Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
        包含参数：
            proxy：动态生成的奥地利对象，一般我们是不用的
            method：当前调用的方法，比如addUser、deleteUser
            args：方法的参数列表，比如addUser的参数。
        我们既然要使用JDK动态代理实现为每个方法添加日志，就要创建一个日志处理类
    3、生成代理对象，并且进行测试
    通过Proxy.newProxyInstance()方法动态的生成代理对象。
    newProxyInstance()方法需要传入3个参数：
        |-ClassLoader loader    真实类的类加载器 target.getClass().getClassLoader();
        |-Class<?>[] interfaces 真实类实现的接口 target.getClass().getInterfaces();
        |-InvocationHandler h   调用处理器，比如我们自己创建的日志处理器LogHandler
JDK动态代理只能代理"实现了某个接口的类"，如果某个类没有接口，那么就代理不了。这时候就需要CGLIB动态代理

CGLIB动态代理，基于继承的。
CGLIB动态代理是一个第三方库，是通过继承被代理类生成代理子类，所以被代理类不能是final修饰的，否则就无法继承，不能代理。
实现步骤：
    0、先导入CGLIB依赖库。
    1、定义没有接口的真实类，假如某个类没有实现任何接口
    2、实现MethodInterceptor接口--处理代理逻辑
        CGLIB动态代理是使用MethodInterceptor接口定义代理的额外操作，核心的方法是intercept()方法
        intercept()方法包含4个参数：
        Object obj          代理对象，子类实例
        java.lang.reflect.Method method  当前调用的方法
        Object[] args   方法的参数
        MethodProxy proxy   方法的代理对象(用来调用父类的方法)
    3、生成代理类对象并且进行测试,过增强器对象Enhancer，生成代理类

动态代理的优缺点：
    优点：不需要手动编写代理类、可以批量处理多个类，比如给所以方法统一添加日志，灵活性很高。
    缺点：逻辑相比静态代理要复杂一些，理解难度也高一些。
    JDK动态代理只能代理接口及其实现类。CGLIB需要依赖第三方库，而且不能代理final类。

使用代理模式的场景：
    Spring AOP面向切面编程，核心就是动态代理。
    日志框架，通过代理模式给所有的方法都自动添加日志输出
    权限控制，每当调用一些敏感方法之前，都是通过代理验证用户的权限。
    缓存，在调用方法之前，可以通过代理检查缓存，避免重复计算。



