首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

设计模式之代理模式

  • 25-03-02 15:21
  • 2791
  • 9897
blog.csdn.net

代理模式是应用最广泛的设计模式之一,例如spring中的aop就是代理模式的实践。通常在java中使用比较广泛的是动态代理模式,其中实现方式比较常用的是jdk动态代理和cglib动态代理。

jdk实现动态代理

利用jdk实现动态代理代码比较简单,需要注意的是基于jdk的动态代理是必须基于接口才可以的,代码如下。

定义接口。

public interface Action {

    public void move();
}
  • 1
  • 2
  • 3
  • 4

定义被代理对象。

public class TargetAction implements Action {
    @Override
    public void move() {
        System.out.println("target doing move");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

实现InvocationHandler定义调用者。

public class InvocationHandlerAction implements InvocationHandler {
    private Action target;

    public InvocationHandlerAction(Action target){
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoker doing");
        return method.invoke(target, args);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

测试代码。

public class JdkProxyTest {
    public static void main(String[] args) throws IOException {
        Action targetAction = new TargetAction();
        Action proxyAction = (Action) Proxy.newProxyInstance(targetAction.getClass().getClassLoader(), targetAction.getClass().getInterfaces(), new InvocationHandlerAction(targetAction));
        proxyAction.move();
        //输出动态生成代理类的字节码文件
        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Action.class});
        FileOutputStream outputStream = new FileOutputStream(new File("D://$Proxy0.class"));
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

根据上面的代码就可以实现一个动态代理逻辑,在InvocationHandler利用反射调用目标对象的方法的前后,可以做出一些逻辑的丰富。

需要注意的上面使用了ProxyGenerator来输出动态生成的字节码文件,内容如下。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import design.mode.proxy.jdk.Action;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Action {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void move() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("design.mode.proxy.jdk.Action").getMethod("move");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

根据输出的字节码文件,可以知道新生成的代理类,实现了Action接口,也就是我们定义的接口,同时实现了接口方法,查看接口方法,发现方法调用逻辑主要是以下代码,h就是我们实现了InvocationHandler接口的类,通过InvocationHandler的invoke方法,进入代理逻辑,实现动态代理。

    public final void move() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

整个动态代理类的生成过程可以归纳为以下一个步骤。

1.根据接口信息,新生成一个代理类的.java文件

2.根据.java,编译生成.class文件

3.classloader读取class文件信息到jvm

4.新建对象,设置InvocationHandler参数。

cglib动态代理实现

定义被代理对象。需要注意,cglib的代理实现不需要基于接口。

public class TargetAction {
    private String word = "default";

    public TargetAction(){

    }

    public TargetAction(String word){
        this.word = word;
    }

    public void move(){
        System.out.println("target doing move" + word);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

定义一个作用类似于InvocationHandler的类。

public class CglibCallBackInvocationHandler implements MethodInterceptor{
    private TargetAction targetAction;

    public CglibCallBackInvocationHandler(TargetAction targetAction){
        this.targetAction = targetAction;
    }

    /**
     * 类似动态代理的InvocationHandler作用
     * @param o
     * @param method
     * @param objects
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("invoker doinig move");
        //return methodProxy.invokeSuper(o, objects);
        return method.invoke(targetAction, objects);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

定义代理类创建器

public class CglibProxyCreator {
    public static <T> T create(Class<T> clazz, MethodInterceptor callbackinvoker){
        Enhancer enhancer = new Enhancer();
        //设置代理什么类
        enhancer.setSuperclass(clazz);
        //设置invoker
        enhancer.setCallback(callbackinvoker);
        return (T) enhancer.create();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

测试代码。

public class CglibTest  {
    public static void main(String[] args) {
        TargetAction targetAction = new TargetAction("defintioin word");
        TargetAction cglibProxy = CglibProxyCreator.create(TargetAction.class, new CglibCallBackInvocationHandler(targetAction));
        cglibProxy.move();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

基本的编码方式与jdk实现的动态代理基本一致,以上就是两种动态代理模式的使用。

注:本文转载自blog.csdn.net的一撸向北的文章"https://blog.csdn.net/qq_20597727/article/details/83594232"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top