代理模式

基本介绍

1.为一个对象提供一个替身,以控制对这个对象的访问,即通过代理对象访问目标对象.

2.被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象

3.形式,

(1)静态代理:需要实现接口

(2)动态代理 / 接口代理 / JDK 代理 :需要实现接口

(3)Cglib 代理 / 子类代理:不需要实现接口,属于动态代理范畴

4.优点:可以在目标对象实现的基础上,增强额外的 功能操作,即扩展目标对象的功能。

 

静态代理

1.原理:定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类

2.思路

(1)定义一个代理接口 ProxyInterface

(2)被代理对象 Target 实现 ProxyInterface

(3)代理对象 Proxy 实现 ProxyInterface

(4)Proxy 聚合到 Target

(5)客户端通过调用 Proxy 的方法来调用 Target

3.优点:在不修改 Target 的功能前提下,能通过 Proxy 对 Target 功能扩展

4.缺点:因为 Proxy 对象需要与 Target 对象实现一样的接口,所以会有很多代理类,一旦接口增加方法,Target 对象与 Proxy 对象都要维护

 

代码示例

public class StaticProxy {//客户端

    public static void main(String[] args) {
        Target target = new Target();
        Proxy proxy = new Proxy(target);
        proxy.method();
    }
}

interface ProxyInterface {//代理接口

    void method();
}

class Target implements ProxyInterface {//被代理类

    @Override
    public void method() {
        System.out.println("执行Target对象方法");
    }
}

class Proxy implements ProxyInterface {//代理类
    private ProxyInterface target;//聚合被代理对象

    public Proxy(ProxyInterface target) {
        this.target = target;
    }

    @Override
    public void method() {
        System.out.println("静态代理开始");
        target.method();
        System.out.println("静态代理提交");
    }
}

 

动态代理 / JDK代理 / 接口代理

1.基本介绍

(1)Proxy 对象不需要实现接口,Target 对象要实现接口

(2)Proxy 对象的生成,是利用 JDK 的 APl,动态的在内存中构建 Proxy 对象

2.JDK 中生成代理对象的 API

(1)代理类所在包:java.lang.reflect.Proxy

(2)JDK 实现代理只需要使用 newProxyInstance 方法,该方法需要接收三个参数

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

/*

ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的

Class<?>[] interfaces:目标对象实现的接口类型,使用泛型方式确认类型

InvocationHandler h:事件处理,执行目标对象的方法时,触发事情处理器的方法,即把当前执行的目标对象的方法作为参数传入

返回值:返回代理对象

*/

3.思路

(1)创建 ProxyFactory ,利用构造器或 setter 传入 Target 对象

(2)实现 getProxyInstance 方法,调用 Proxy 中的 newProxyInstance:以反射机制传参:ClassLoader loader、Class<?>[] interfaces;以 new 方式传参:InvocationHandler

(3)newProxyInstance 利用反射机制返回编译类型为 Object 的代理对象,即代理对象是 Target 的 Class 反射出来的,且运行类型为 JDK 中的 Proxy 类的匿名内部类

(4)重写 InvocationHandler 的 invoke,代理对象聚合了 InvocationHandler

(5)代理对象调用 invoke 方法,即代理对象利用反射机制调用 Target 对象的方法

public Object invoke(Object proxy, Method method, Object[] args)

/*

Object proxy:代理对象的实例

Method method:代理接口的方法

Object[] args:代理接口方法的参数,可能为null

返回值:代理接口方法的返回值,可能为null

*/

 

代码示例

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxy {//客户端

    public static void main(String[] args) {
        Target target = new Target();
        //传入目标对象
        ProxyFactory proxyFactory = new ProxyFactory(target);
        //创建代理对象,强制转换为ProxyInterface,才能调用 Target 方法
        ProxyInterface proxyInstance = (ProxyInterface) proxyFactory.getProxyInstance();
        //输出proxyInstance是属于哪个类的Class对象:Target@66d3c617
        System.out.println("代理对象属于 " + proxyInstance + " 类的Class对象");
        //输出proxyInstance的运行类型:class $Proxy0
        System.out.println("代理对象的运行类型:" + proxyInstance.getClass());
        proxyInstance.method1();
        proxyInstance.method2();

    }
}

interface ProxyInterface {//代理接口

    void method1();

    void method2();
}

class Target implements ProxyInterface {//被代理类

    @Override
    public void method1() {
        System.out.println("执行Target对象的方法1");
    }

    @Override
    public void method2() {
        System.out.println("执行Target对象的方法2");
    }
}

class ProxyFactory {//代理工厂类
    private Object target;//目标对象

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //给目标对象生成代理对象
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //反射机制调用目标对象的方法
                        Object returnValue = method.invoke(target, args);
                        //返回目标对象方法的返回值
                        return returnValue;
                    }
                });
    }
}

 

Cglib 代理 / 子类代理

1.基本介绍

(1)使用 Target 对象的子类来实现代理,在内存中构建一个子类对象从而实现对 Target 对象功能扩展

(2)Cglib 是一个高性能的代码生成包,可以在运行期扩展 Java 类与实现  Java 接口,广泛应用于 AOP 的框架,如 Spring AOP,实现方法拦截

(3)Cglib 包的底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类

2.在 AOP 编程中如何选择代理模式

(1)目标对象需要实现接口,用 JDK 代理

(2)目标对象不需要实现接口,用 Cglib 代理

3.事项

(1)引入 cglib 的 jar 文件

(2)在内存中动态构建子类,注意,Target 类不能为 final ,否则报错:java.lang.IllegalArgumentException

(3)Target 对象的方法若为 final / static,那么就不会被拦截,即代理对象不会执行 Target 对象独有的方法

(4)Proxy 实现 MethodInterceptor 接口,getInstance 方法为 Target 对象创建代理对象,重写 intercept 方法

(5)代理对象 触发 intercept ,调用 invoke,即代理对象调用 Target 对象的方法

 

代码示例

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy {//客户端

    public static void main(String[] args) {
        //创建目标对象
        Target target = new Target();
        //通过代理工厂创建代理对象
        Target proxyInstance = (Target) new ProxyFactory(target).getProxyInstance();
        //通过代理对象调用目标对象方法
        proxyInstance.method();
    }
}

class Target {//被代理类

    public void method() {
        System.out.println("执行Target方法");
    }
}

class ProxyFactory implements MethodInterceptor {//代理工厂类
    private Object target;//目标对象

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //返回代理对象
    public Object getProxyInstance() {
        //创建工具类
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建子类对象,即代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib代理开始");
        //反射机制调用目标对象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("cglib代理结束");
        //返回目标对象方法的返回值
        return returnValue;
    }
}

 

变体

1.防火墙代理:内网通过代理穿透防火墙,实现对公网的访问

2.缓存代理:如,请求图片文件等资源时,先到缓存代理取,若取不到资源,再到公网或者数据库取,然后缓存

3.远程代理:通过网络和真正的远程对象沟通信息,远程对象的本地代表可以调用远程对象当本地对象

4.同步代理:主要使用在多线程编程中,完成多线程间同步工作

posted @   半条咸鱼  阅读(44)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示