【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
出自【进步*于辰的博客】
参考笔记一,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()
。
最后
本文中的例子是为了阐述静态代理和动态代理的实现思想、方便大家理解而简单举出的,不一定有实用性,大家自行扩展。
本文完结。
发表评论