当前位置: 代码网 > it编程>软件设计>设计模式 > [Java]静态代理与动态代理(基于JDK1.8)

[Java]静态代理与动态代理(基于JDK1.8)

2024年05月12日 设计模式 我要评论
本篇文章主要是对静态代理和动态代理实现思路的简述,以示例为主,少涉及理论。如果文中阐述不全或不对的,多多交流。 ...

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)

出自【进步*于辰的博客

参考笔记一,p83。

1、简介

什么是代理模式?“代理模式”指通过为目标对象(原代码)创建代理对象,将附加功能(附加代码)注入目标对象的方法,从而实现附加功能的设计模式,分为静态代理和动态代理。

什么是静态代理?“静态代理”指为目标类手动创建代理类的代理方式。

什么是动态代理?“动态代理”指在不变动原代码的情况下,通过反射动态创建代理对象的代理方式。(注:“反射”是动态代理的底层,不可见)

2、静态代理的两种形式

2.1 面向接口

特点:目标对象与代理对象隶属于同一接口。

看下述代码:
1、公共接口:目标类和代理类的公共接口。

interface iservice {
    int transfer(int money);
}

2、目标类。

class target implements iservice {
    @override
    public int transfer(int money) {
        system.out.println("转账金额:" + money);
        return 1;
    }
}

3、代理类。

class proxy implements iservice {
    private target target;
    public proxy(target target) {
        this.target = target;
    }

    @override
    public int transfer(int score) {
        system.out.println("打开事务");// 附加功能
        int x = target.transfer(score);
        system.out.println("关闭事务");
        return x;
    }
}

测试。

class test {
    public static void main(string[] args) {
        proxy proxy = new proxy(new target());// 创建代理对象
        int x = proxy.transfer(10);
        if (x > 0)
            system.out.println("转账成功");
        else
            system.out.println("转账失败");
    }
}

测试结果:
在这里插入图片描述

2.2 面向继承

特点:目标对象与代理对象是继承关系,代理对象继承于目标对象。

看下述代码:
1、目标类。

class target {
    public int transfer(int money) {
        system.out.println("转账金额:" + money);
        return 1;
    }
}

3、代理类。

class proxy extends target {
    @override
    public int transfer(int money) {
        system.out.println("打开事务");// 附加功能
        int x = super.transfer(money);
        system.out.println("关闭事务");
        return x;
    }
}

测试。

class test {
    public static void main(string[] args) {
        proxy proxy = new proxy();// 创建代理对象
        int x = proxy.transfer(20);
        if (x > 0)
            system.out.println("转账成功");
        else
            system.out.println("转账失败");
    }
}

测试结果:
在这里插入图片描述

3、动态代理的两种形式

静态代理需要手动生成代理类,进而创建代理对象,很冗余。换个思路,反射可以根据 class 信息创建实例,故可以通过反射为目标对象创建代理对象,则无需创建代理类,这就是“动态代理”。

3.1 jdk动态代理

特点:面向接口,隶属于java api

看下述代码:
1、公共接口。

/**
 * 目标对象与代理对象的公共接口
 * 注:因为jdk动态代理面向接口,故目标对象和代理对象实现于同一接口
 */
interface iservice {
    int transfer(int money);
}

2、目标类。

class target implements iservice {
    @override
    public int transfer(int money) {
        system.out.println("转账金额:" + money);
        return 1;
    }
}

测试。

class test {
    public static void main(string[] args) {
        target target = new target();
        /**
         * 通过 newproxyinstance() 创建代理对象
         *     第一个参数是目标对象的类加载器,指定为哪个目标对象创建代理对象;
         *     第二个参数是目标对象实现的接口,指定目标对象和代理对象的公共接口;
         *     第三个参数是拦截器对象,指定用哪个拦截器来创建代理对象,需要实现 invocationhandler 接口。
         */
        // 由于代理对象 proxy 是通过反射创建于jvm,并无类存在,故要上转为公共接口 iservice
        iservice proxyinstance = (iservice) proxy.newproxyinstance(target.getclass().getclassloader(),
                target.getclass().getinterfaces(),
                new invocationhandler() {
                    /**
                     * 代理(调用 transfer())时执行的方法
                     * @param proxy  代理对象,即 proxyinstance,暂不知如何使用
                     * @param method 目标对象的 method 的 class 对象
                     * @param args   目标对象的 method 的形参数组
                     */
                    @override
                    public object invoke(object proxy, method method, object[] args) throws throwable {
                        system.out.println("打开事务");// 附加功能
                        // invoke() 是反射中 method 对象执行时调用的方法,故动态代理是通过反射调用目标对象被代理的方法
                        object result = method.invoke(target, args);
                        system.out.println("关闭事务");
                        return result;
                    }
                });// 创建代理对象
        int x = proxyinstance.transfer(50);
        if (x > 0)
            system.out.println("转账成功");
        else
            system.out.println("转账失败");
    }
}


测试结果:
在这里插入图片描述
可以用lambda表达式进行简化。

3.2 cglib动态代理

特点:面向继承,隶属于spring api

看下述代码:
1、目标类。

class target {
    public int transfer(int money) {
        system.out.println("转账金额:" + money);
        return 1;
    }
}

2、代理类。

/**
 * cglib动态代理类,需实现接口 methodinterceptor
 */
class dynamicproxy implements methodinterceptor {
    private object target;
    public dynamicproxy(object target) {
        this.target = target;
    }
    public object createproxy() {
        enhancer proxy = new enhancer();// enhancer 类是一种类生成器
        proxy.setcallback(this);// 设置拦截器,即自身
        proxy.setsuperclass(target.getclass());// 设置父类,指定为哪个目标对象创建代理对象
        return proxy.create();// 创建代理对象
    }

    /**
     * 代理(调用 transfer())时执行的方法
     * @param proxy       代理对象,即 proxyinstance,暂不知如何使用
     * @param method      目标对象的 method 的 class对象
     * @param args        目标对象的 method 的参数数组
     * @param methodproxy 代理方法,即 target.transfer(),暂不知如何使用
     */
    @override
    public object intercept(object proxy, method method, object[] args, methodproxy methodproxy) throws throwable {
        system.out.println("打开事务");// 附加功能
        // invoke() 是反射中 method 对象执行时调用的方法,故动态代理是通过反射调用目标对象被代理的方法
        object result = method.invoke(target, args);
        system.out.println("关闭事务");
        return result;
    }
}

测试。

class test {
    public static void main(string[] args) {
        target target = new target();
        target proxyinstance = (target) new dynamicproxy(target).createproxy();
        int x = proxyinstance.transfer(100);
        if (x > 0)
            system.out.println("转账成功");
        else
            system.out.println("转账失败");
    }
}


测试结果:
在这里插入图片描述

同样可以用lambda表达式进行简化,不过代理对象的创建(proxy.create())需要对 enhancer 类的属性进行一些设置,故进行了封装。

注意:两种动态代理皆可拦截所有方法,如:tostring()hashcode()。但不能拦截由 final 修饰的方法,如:getclass()

最后

本文中的例子是为了阐述静态代理和动态代理的实现思想、方便大家理解而简单举出的,不一定有实用性,大家自行扩展。

本文完结。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com