代理模式代理模式

目录

1、使用场景

2、静态代理

3、动态代理

JDK动态代理

CGlib 动态代理实现


1、使用场景

使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。

2、静态代理

代理模式代理模式_第1张图片

NO.1 抽象接口:定义视频播放器接口Player

public interface Player {
    void loadVideo(String filename);
    void playVideo(String filename);
}

NO.2 真实类:定义接口实现类VPlayer

public class VPlayer implements Player {
    @Override
    public void loadVideo(String filename) {
        System.out.println("加载MP4视频文件:"+filename);
    }

    @Override
    public void playVideo(String filename) {
        System.out.println("播放MP4视频:"+filename);
    }
}

NO.3 代理类:定义代理类VPlayerProxy,实现同样的接口,并且引入目标对象

public class VPlayerProxy implements Player {

    private Player player;

    public VPlayerProxy(Player player) {
        this.player = player;
    }

    @Override
    public void loadVideo(String filename) {
        player.loadVideo(filename);
    }

    @Override
    public void playVideo(String filename) {
        player.playVideo(filename);
    }
}

NO.4 客户端调用

public class Client1 {
    public static void main(String[] args) {
        //直连方式
        Player vplay=new VPlayer();
        vplay.playVideo("aaa.mp4");
        System.out.println();

        //代理方式
        Player proxy=new VPlayerProxy(vplay);
        proxy.loadVideo("aaa.mp4");
        proxy.playVideo("aaa.mp4");

    }
}

代理模式代理模式_第2张图片

3、动态代理

JDK动态代理

JDK动态代理是基于接口实现的代理,只能代理实现了接口的类。

在运行时动态生成一个代理对象,,同时还可以在方法调用前后执行额外的增强处理。JDK动态代理通过反射机制实现代理功能,其原理分为以下几个步骤:

(1)、创建实现InvocationHandler接口的代理类工厂:在调用Proxy类的静态方法newProxyInstance时,会动态生成一个代理类。
(2)、在代理对象的方法被调用时,JVM会自动调用代理类的invoke方法。在invoke方法中,可以根据需要执行各种逻辑,比如添加日志、性能统计、事务管理等。
(3)、invoke方法调用:在invoke方法中,通过反射机制调用目标对象的方法,并返回方法的返回值。在调用目标对象的方法前后,可以执行额外的逻辑。

通用实现代码

public class JDKProxyFactory implements InvocationHandler {

    //需要被代理的对象
    private Object object;

    public JDKProxyFactory(Object object) {
        this.object = object;
    }

    @SuppressWarnings("unchecked")
    public  T getProxy(){
        return (T) Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),//当前线程的上下文ClassLoader
                object.getClass().getInterfaces(), //代理需要实现的接口
                this); // 处理器自身
    }
	
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
		//进行方法匹配,调用对应方法名的方法
        if ("loadVideo".equals(method.getName())) {
            result=method.invoke(object, args);
        }

        if ("playVideo".equals(method.getName())) {
            System.out.println("前置增强");
            result=method.invoke(object, args);
            System.out.println("后置增强");
        }
        return result;
    }
}

客户端调用

public class Client2 {
    public static void main(String[] args) {
        Player player=new VPlayer();
        Player proxy=new JDKProxyFactory(player).getProxy();
        proxy.loadVideo("aaa.mp4");
        proxy.playVideo("aaa.mp4");

/*      或者
        Player p=new VPlayer();
        Player o = (Player) Proxy.newProxyInstance(
                p.getClass().getClassLoader(),
                p.getClass().getInterfaces(),
                new VPlayerProxyFactory(p)
        );
        o.loadVideo("aaaa.mp4");
*/
    }
}

代理模式代理模式_第3张图片

CGlib 动态代理实现

CGlib方式是基于继承实现的代理,它不是指真实类需要继承某个父类,而是生成的代理类作为真实类的子类去代理父类,即代理类继承自真实类。这种方式不需实现接口,可以作为JDK代理方式的补充方案。

CGLIB(Code Generation Library)可以在运行时动态生成目标类的子类作为代理类,并覆盖其中的方法来实现代理功能。与Java自带的JDK动态代理不同,CGlib动态代理可以代理没有实现接口的类。其原理分为以下几个步骤:

(1)、创建Enhancer对象:Enhancer是CGLIB库中用于动态生成子类的主要类。通过创建Enhancer对象并设置需要代理的目标类、拦截器等参数,可以生成一个代理类。

 (2)、调用代理对象:通过调用代理对象的方法,会触发拦截器的intercept方法。在intercept方法中,可以根据需要执行各种逻辑,比如添加日志、性能统计、事务管理等。

单独定义一个没有接口的真实类APlayer

//音频播放器
public class APlayer {
    public void loadAudio(String filename) {
        System.out.println("加载MP3音频文件:"+filename);
    }

    public void playAudio(String filename) {
        System.out.println("播放MP3:"+filename);
    }
}

通用实现代码

public class CglibProxyFactory implements MethodInterceptor {

    @SuppressWarnings("unchecked")
    public  T getProxy(Class clazz) {
        Enhancer en = new Enhancer();
        //设置代理的父类
        en.setSuperclass(clazz);
        //设置方法回调
        en.setCallback(this);
        //创建代理实例
        return (T)en.create();
    }

    @Override
    //参数中的object是目标对象,method和args是目标对象的方法和参数,methodProxy是方法代理
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result = null;

        if ("loadAudio".equals(method.getName())) {
            //通过继承的方法实现代理,因此这里调用invokeSuper
            result = methodProxy.invokeSuper(object, args);
        }
        if ("playAudio".equals(method.getName())) {
            result = methodProxy.invokeSuper(object, args);
        }
        return result;
    }
}

客户端调用

public class Client3 {
    public static void main(String[] args) {
        APlayer aplayer=new APlayer();
        APlayer proxy = new CglibProxyFactory().getProxy(aplayer.getClass());
        //验证代理类的父类
        System.out.println("代理类的父类:"+proxy.getClass().getSuperclass().getSimpleName());
        System.out.println();

        proxy.loadAudio("荷塘月色.mp3");
        proxy.playAudio("荷塘月色.mp3");
    }
}

代理模式代理模式_第4张图片

你可能感兴趣的:(设计模式,代理模式)