| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 | 代理模式    代理模式(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   调用处理器,比如我们自己创建的日志处理器LogHandlerJDK动态代理只能代理"实现了某个接口的类",如果某个类没有接口,那么就代理不了。这时候就需要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面向切面编程,核心就是动态代理。    日志框架,通过代理模式给所有的方法都自动添加日志输出    权限控制,每当调用一些敏感方法之前,都是通过代理验证用户的权限。    缓存,在调用方法之前,可以通过代理检查缓存,避免重复计算。
 |