• 5.代理模式


    【基本介绍】

      代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象,这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

      被代理的对象可以是远程对象,创建开销大的对象或者需要安全控制的对象。

      代理模式分类:静态代理、动态代理(JDK代理、接口代理)和Cglib代理(可以在内存动态的创建对象,而不需要实现接口,它属于动态代理的范畴)。

    1.静态代理

      使用静态代理时,需要定义接口或者弗雷,被代理对象和代理对象一起实现同一接口或者继承同一父类

    1 //接口
    2 public interface ITeacherDao {
    3     void teach(); // 授课的方法
    4 }
    同一接口
    1 public class TeacherDao implements ITeacherDao {
    2     @Override
    3     public void teach() {
    4         // TODO Auto-generated method stub
    5         System.out.println(" 老师授课中  。。。。。");
    6     }
    7 }
    被代理对象
     1 //代理对象,静态代理
     2 public class TeacherDaoProxy implements ITeacherDao{
     3     
     4     private ITeacherDao target; // 目标对象,通过接口来聚合
     5 
     6     //构造器
     7     public TeacherDaoProxy(ITeacherDao target) {
     8         this.target = target;
     9     }
    10 
    11     @Override
    12     public void teach() {
    13         // TODO Auto-generated method stub
    14         System.out.println("开始代理  完成某些操作。。。。。 ");//方法
    15         target.teach();
    16         System.out.println("提交。。。。。");//方法
    17     }
    18 }
    代理对象
     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         // TODO Auto-generated method stub
     5         //创建目标对象(被代理对象)
     6         TeacherDao teacherDao = new TeacherDao();
     7         
     8         //创建代理对象, 同时将被代理对象传递给代理对象
     9         TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
    10         
    11         //通过代理对象,调用到被代理对象的方法
    12         //即:执行的是代理对象的方法,代理对象再去调用目标对象的方法 
    13         teacherDaoProxy.teach();
    14         /*
    15         开始代理  完成某些操作。。。。。 
    16          老师授课中  。。。。。
    17         提交。。。。。
    18          */
    19     }
    20 }
    测试

      优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展

      缺点:因为代理对象要与目标对象实现一样的接口,所以会有很多代理类。一旦接口增加方法,目标对象和代理对象都需要维护。

    2.动态代理

      代理对象不需要实现接口,但是目标对象需要实现接口。代理对象的生成也是利用JDK的API,动态地在内存中构建代理对象,所以动态代理也叫做JDK代理、接口代理。

      JDK中生成代理对象地API,代理类所在包:java.lang.reflect.Proxy,JDK使用newProxyInstance方法,需要三个参数,完整写法为

    static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

    1 //接口
    2 public interface ITeacherDao {
    3 
    4     void teach(); // 授课方法
    5     void sayHello(String name);
    6 }
    接口
     1 public class TeacherDao implements ITeacherDao {
     2 
     3     @Override
     4     public void teach() {
     5         // TODO Auto-generated method stub
     6         System.out.println(" 老师授课中.... ");
     7     }
     8 
     9     @Override
    10     public void sayHello(String name) {
    11         // TODO Auto-generated method stub
    12         System.out.println("hello " + name);
    13     }
    14     
    15 }
    被代理对象
     1 public class ProxyFactory {
     2 
     3     //维护一个目标对象 , Object
     4     private Object target;
     5 
     6     //构造器 , 对target 进行初始化
     7     public ProxyFactory(Object target) {
     8         
     9         this.target = target;
    10     } 
    11     
    12     //给目标对象 生成一个代理对象
    13     public Object getProxyInstance() {
    14         //说明
    15         /*
    16          *  public static Object newProxyInstance(ClassLoader loader,
    17                                           Class<?>[] interfaces,
    18                                           InvocationHandler h)
    19                                           
    20             //1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
    21             //2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
    22             //3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
    23          */
    24         return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
    25                 target.getClass().getInterfaces(), 
    26                 new InvocationHandler() {
    27                     
    28                     @Override
    29                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    30                         // TODO Auto-generated method stub
    31                         System.out.println("JDK代理开始~~");
    32                         //反射机制调用目标对象的方法
    33                         Object returnVal = method.invoke(target, args);
    34                         System.out.println("JDK代理提交");
    35                         return returnVal;
    36                     }
    37                 }); 
    38     }
    39 }
    代理类
     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         // TODO Auto-generated method stub
     5         //创建目标对象
     6         ITeacherDao target = new TeacherDao();
     7         
     8         //给目标对象,创建代理对象, 可以转成 ITeacherDao
     9         ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
    10     
    11         // proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
    12         System.out.println("proxyInstance=" + proxyInstance.getClass());
    13         
    14         //通过代理对象,调用目标对象的方法
    15         //proxyInstance.teach();
    16         
    17         proxyInstance.sayHello(" tom ");
    18         /*
    19         proxyInstance=class com.sun.proxy.$Proxy0
    20         JDK代理开始~~
    21         hello  tom 
    22         JDK代理提交
    23          */
    24     }
    25 }
    测试

    3.Cglib代理

      静态代理和动态代理都要求被代理对象实现一个接口,但是有时被代理对象并没有实现接口,此时可以使用Cglib代理。

      Cglib代理也叫做子类代理,他是内存中都剪一个子类对象从而实现对目标对象地功能扩展。Cglib是一个功能强大的代码生成包,可以在运行期扩展Java类与实现Java接口,它广泛的被许多AOP框架使用,例如Spring AOP实现方法拦截。

      如果目标对象需要实现接口=》动态代理    如果目标对象不需要实现接口=》Cglib代理   

      如果目标对象地方法时final或者static,那么就不会被拦截,即不会执行目标对象额外的业务方法。

     【实现步骤】

    ①导包

    ②UML

     代理对象需要实现net.sf.cglib.proxy.MethodInterceptor接口

    1 public class TeacherDao {
    2 
    3     public String teach() {
    4         System.out.println(" 老师授课中  , 我是cglib代理,不需要实现接口 ");
    5         return "hello";
    6     }
    7 }
    被代理对象
     1 public class ProxyFactory implements MethodInterceptor {
     2 
     3     //维护一个目标对象
     4     private Object target;
     5     
     6     //构造器,传入一个被代理的对象
     7     public ProxyFactory(Object target) {
     8         this.target = target;
     9     }
    10 
    11     //返回一个代理对象:  是 target 对象的代理对象
    12     public Object getProxyInstance() {
    13         //1. 创建一个工具类
    14         Enhancer enhancer = new Enhancer();
    15         //2. 设置父类
    16         enhancer.setSuperclass(target.getClass());
    17         //3. 设置回调函数
    18         enhancer.setCallback(this);
    19         //4. 创建子类对象,即代理对象
    20         return enhancer.create();
    21         
    22     }
    23     
    24     //重写  intercept 方法,会调用目标对象的方法
    25     @Override
    26     public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
    27         // TODO Auto-generated method stub
    28         System.out.println("Cglib代理模式 ~~ 开始");
    29         Object returnVal = method.invoke(target, args);
    30         System.out.println("Cglib代理模式 ~~ 提交");
    31         return returnVal;
    32     }
    33 
    34 }
    代理对象
     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         // TODO Auto-generated method stub
     5         //创建目标对象
     6         TeacherDao target = new TeacherDao();
     7         //获取到代理对象,并且将目标对象传递给代理对象
     8         TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();
     9 
    10         //执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
    11         String res = proxyInstance.teach();
    12         System.out.println("res=" + res);
    13         /*
    14         Cglib代理模式 ~~ 开始
    15         老师授课中  , 我是cglib代理,不需要实现接口
    16         Cglib代理模式 ~~ 提交
    17         res=hello
    18          */
    19     }
    20 
    21 }
    测试
  • 相关阅读:
    GDB 用法
    C编程规范
    PHP面向对象
    cron定时任务
    Apatche配置基础
    正则表达式笔记
    PHP在windows下命令行方式
    面试题
    struts与ajax的关系
    ORACLE DUAL表详解
  • 原文地址:https://www.cnblogs.com/qmillet/p/12112033.html
Copyright © 2020-2023  润新知