设计模式学习之--代理模式
2015-08-09 16:07
375 查看
代理模式,顾名思义,意思和我们日常生活中的代理差不多,举一个最简单的例子,我们知道,我们的火车站购票有很多的火车票代售点,这个火车票代售点可以代替我们的火车站的售票处让我们买票,当然,代售点相比于火车站售票点又可以提供电话订票和提前预定,这样,火车票代售点就基本可以实现火车站售票点的基本功能,同时还可以提供相对于火车站售票点其他的功能。那么,我们的设计模式中的代理模式就是这个意思。
在我们的程序中,许多类的方法中我们总需要一些额外的共同的功能,比如日志和性能优化操作,如果在所有 这些类中都加入这些相同的功能,会使我们的程序变得很冗余,这时,我们的代理模式就起作用了,代理模式在我们的程序中不会影响其原方法的执行,我们用一个代理执行类原有的功能,同时加入我们的共同的功能模块,不同类都使用这个总的实体产生代理,这样我们的程序就变得很健壮了(这也是spring中的AOP思想的实现原理)。
在我们的初始学习中,我们先了解两种基本的代理模式,静态代理和动态代理:
静态代理是继承目标类产生一个代理类,然后在目标类的方法中加入我们的其它功能。
动态代理是目标类和代理类实现同一个接口,在代理类中添加一个目标类的引用添加新的功能。
当然这些基础的代理只能对特定的类实现不同功能的代理,这种自然是不合理的,为此,我们的动态代理在我们的jdk中就提供了一个可以为所有对象生成代理的接口,只要实现了这个接口,就可以添加功能并返回这个目标类的代理。
另一种已经实现的通用代理就是我们的cglib提供的动态代理。
这两种动态代理都是需要一个代理类实现一个接口,然后将目标类传入代理类用代理类生产代理对象,但两者是有区别的。
jdk动态代理:(jdk动态代理生成目标代理类传入的必须是接口,所以必须目标类必须要实现一个接口)
这里举个工厂生产的例子:
我们的代理类:
下面是cglib的动态代理,使用cglib代理需要一个jar包,这里提供下载地址:
cglib的代理类也是需要实现一个接口,我们还是用这个工厂的例子来展示:
cglib代理(使用它的目标类不需要实现接口,它的原理是通过目标类实现一个子类来实现的)
用法和jdk动态代理是一样的,下面给出代理类:
用法是一样的 。代理模式就是这两个牛逼点了了。
在我们的程序中,许多类的方法中我们总需要一些额外的共同的功能,比如日志和性能优化操作,如果在所有 这些类中都加入这些相同的功能,会使我们的程序变得很冗余,这时,我们的代理模式就起作用了,代理模式在我们的程序中不会影响其原方法的执行,我们用一个代理执行类原有的功能,同时加入我们的共同的功能模块,不同类都使用这个总的实体产生代理,这样我们的程序就变得很健壮了(这也是spring中的AOP思想的实现原理)。
在我们的初始学习中,我们先了解两种基本的代理模式,静态代理和动态代理:
静态代理是继承目标类产生一个代理类,然后在目标类的方法中加入我们的其它功能。
动态代理是目标类和代理类实现同一个接口,在代理类中添加一个目标类的引用添加新的功能。
当然这些基础的代理只能对特定的类实现不同功能的代理,这种自然是不合理的,为此,我们的动态代理在我们的jdk中就提供了一个可以为所有对象生成代理的接口,只要实现了这个接口,就可以添加功能并返回这个目标类的代理。
另一种已经实现的通用代理就是我们的cglib提供的动态代理。
这两种动态代理都是需要一个代理类实现一个接口,然后将目标类传入代理类用代理类生产代理对象,但两者是有区别的。
jdk动态代理:(jdk动态代理生成目标代理类传入的必须是接口,所以必须目标类必须要实现一个接口)
这里举个工厂生产的例子:
package com.yc.biz; //目标类的接口 public interface ProductBiz { public void addProduct(); public void delProduct(); public void updateProduct(); public void findall(); } package com.yc.biz; //目标类 public class ProductBizImpl implements ProductBiz { @Override public void addProduct() { System.out.println("*******************************"); System.out.println("添加产品"); System.out.println("*******************************"); } @Override public void delProduct() { System.out.println("*******************************"); System.out.println("删除产品"); System.out.println("*******************************"); } @Override public void updateProduct() { System.out.println("*******************************"); System.out.println("修改产品"); System.out.println("*******************************"); } @Override public void findall() { System.out.println("*******************************"); System.out.println(" 查询所有的产品"); System.out.println("*******************************"); } }我们要在这个类上加上权限的检查(代理模式这时候如果所有业务类都需要这功能时,全部用这个代理类生产目标类就可以加上权限检查了,节省了很多代码)
我们的代理类:
package com.yc.advice; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //这个类是一个切面类, 完成的功能是向目标类的目标方法加入功能( 增强) public class RightAdvice implements InvocationHandler { //代理模式中一定要有目标类的引用 private Object targetObject; //注意,这个就是目标类的引用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName=method.getName(); if( methodName.startsWith("add") || methodName.startsWith("del")|| methodName.startsWith("update") || methodName.startsWith("modify") ){ //在invoke中加入您要增强的代码 check(); //前置增强,在激活调用对应方法前加入的代码 } //调用目标的对应的方法,这里通过反射激活目标类的方法 Object returnValue=method.invoke(targetObject, args); // object is not an instance of declaring class return returnValue; } //创建一个方法来完成创建代理对象 public Object createInstance( Object targetObject ){ this.targetObject=targetObject; //生成一个代理对象.. // 生成一个代理对象,这个代理对象是根据 目标对象的接口生成的。 Object obj= Proxy.newProxyInstance( targetObject.getClass().getClassLoader() , targetObject.getClass().getInterfaces() , this ); //在客户端,我们调用 createInstance()得到一个代理对象,再调用这个代理对象的 方法. -> 它就会自动加调( 因为this ) -> invoke return obj; } //增强 private void check(){ System.out.println("***********************************"); System.out.println("权限检查"); System.out.println("***********************************"); } }测试类:
package com.yc.biz; import com.yc.advice.LogAdvice; import com.yc.advice.RightAdvice; public class Test1 { public static void main(String[] args) { RightAdvice ra=new RightAdvice(); ProductBiz pb=new ProductBizImpl(); ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb); productBizProxy.addProduct(); productBizProxy.delProduct(); productBizProxy.updateProduct(); productBizProxy.findall(); } }这个就是jdk的动态代理。
下面是cglib的动态代理,使用cglib代理需要一个jar包,这里提供下载地址:
cglib的代理类也是需要实现一个接口,我们还是用这个工厂的例子来展示:
cglib代理(使用它的目标类不需要实现接口,它的原理是通过目标类实现一个子类来实现的)
用法和jdk动态代理是一样的,下面给出代理类:
package com.yc.advice; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; //这个类是一个切面类, 完成的功能是向目标类的目标方法加入功能( 增强) public class RightAdvice implements MethodInterceptor { //代理模式中一定要有目标类的引用 private Object targetObject; //注意,这个就是目标类的引用 @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy arg3) throws Throwable { String methodName=method.getName(); if( methodName.startsWith("add") || methodName.startsWith("del")|| methodName.startsWith("update") || methodName.startsWith("modify") ){ //在invoke中加入您要增强的代码 check(); //前置增强 } //调用目标的对应的方法 Object returnValue=method.invoke(targetObject, args); // object is not an instance of declaring class return returnValue; } //创建一个方法来完成创建代理对象 public Object createInstance( Object targetObject ){ this.targetObject=targetObject; // => Object Enhancer enhancer=new Enhancer(); enhancer.setSuperclass( targetObject.getClass() ); //enhancer.setClassLoader( targetObject.getClass().getClassLoader() ); enhancer.setCallback( this ); return enhancer.create(); //创建代理类对象. } //增强 private void check(){ System.out.println("***********************************"); System.out.println("权限检查"); System.out.println("***********************************"); } }
用法是一样的 。代理模式就是这两个牛逼点了了。
相关文章推荐
- 背单词App开发日记5(下)
- POJ1426——DFS——Find The Multiple
- 彻底理解ThreadLocal
- AVL
- 线段树总结(单点更新,区间更新,区间求和,区间求最值)
- Tarena - 循环嵌套和数组的练习
- 为什么选择Nginx
- 为什么选择Nginx
- 异常图结构
- NOJ1083 ACM竞赛之输入输出(字符串输入与输出)
- HDU 4739
- 回溯法应用
- Avoid The Lakes
- PowerDesigner中列表显示TABLE的NAME而不是CODE
- 答读者问(5):关于数学程序猿的作用、r \\ u0026研发工作的实践要求和问题,如求职的影响
- 第19章 网络通信----UDP程序设计基础
- 【3】数字数组中只出现一次
- 打开系统设置界面
- Seeding
- activity启动模式区别和优化