程序员设计模式

设计模式之代理模式(结构型)

2019-01-19  本文已影响4人  smileNicky

第一章

1.1 模式定义

代理模式:代理模式就是引入一个代理对象,通过代理对象实现对原对象的引用。代理模式是一种对象结构型。

1.2 代理模式包含如下角色

[图片上传失败...(image-d1d75e-1547891819525)]

1.3 模式例子

public class Proxy implements Subject
{
    private RealSubject realSubject = new RealSubject();
    public void preRequest()
    {…...}
    public void request()
    {
        preRequest();
        realSubject.request();
        postRequest();
    }
    public void postRequest()
    {……}
} 

1.4 模式类型

来自:《设计模式》一书归纳分类

  • 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)。
  • 虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
  • Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
  • 保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
  • 缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
  • 防火墙(Firewall)代理:保护目标不让恶意用户接近。
  • 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
  • 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。

下面介绍一下静态代理和动态代理

代理模式分为静态代理和动态代理 • 静态代理:静态代理就是编译阶段就生成代理类来完成对代理对象的一系列操作。
• 动态代理:动态代理是指在运行时动态生成代理类。即,代理类的字节码将在运行时生成并载入当前代理的 ClassLoader。

第二章 静态代理

静态代理:静态代理就是编译阶段就生成代理类来完成对代理对象的一系列操作。
主题接口:

public   interface Subject  {    
    abstract   public   void  request(); 
}   

目标对象:

public   class  RealSubject  implements Subject  {                     
   public   void  request()  { 
       System.out.println( " From real subject. " );     
   }  
}  

代理对象:

public   class  StaticProxySubject  implements Subject  { 
    private  RealSubject  realSubject;  // 以真实角色作为代理角色的属性  
    public  ProxySubject()  { }  
    public  void  request()  {  // 该方法封装了真实对象的request方法        
    //懒加载,用的时候才加载
    if ( realSubject  ==   null  )  { 
        realSubject  =   new  RealSubject();        
    }   
    realSubject.request();  // 此处执行真实对象的request方法   
   } 
}

编写客户端类:

public class Client{
    StaticProxySubject sps = new StaticProxySubject();
    sps.request();
}

第三章 动态代理

动态代理:动态代理是指在运行时动态生成代理类。即,代理类的字节码将在运行时生成并载入当前代理的 ClassLoader。
生成动态代理的方法有很多: JDK中自带动态代理,CGlib, javassist等。

3.1 JDK动态代理

Proxy类。该类即为动态代理类,该类最常用的方法为:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

newProxyInstance()方法用于根据传入的接口类型interfaces返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示被代理类实现的接口列表,第三个参数h表示所指派的调用处理程序类。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyInvocationHandler implements InvocationHandler {
    private Class<?> target;//委托类
    public MyInvocationHandler(Class<?> target){
        this.target=target;
    }
    //实际执行类bind
    public  Object bind(Class<?> target){
        //利用JDK提供的Proxy实现动态代理
        return  Proxy.newProxyInstance(target.getClassLoader(),
                new Class[]{target},this);
    }
    
    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        /**代理环绕**/
        //执行实际的方法
        Object invoke = method.invoke(target, args);
        return invoke;
    }
}

3.2 CGLIB动态代理

CGLIB动态代理实现相关类需要在项目中导入 cglib-nodep-2.1_3.jar ,主要涉及两个类:
MethodInterceptor接口。它是代理实例的调用处理程序实现的接口,该接口中定义了如下方法:public Object intercept(Object proxy, Method method, Object[] arg2, MethodProxy mp);

intercept()方法中第一个参数proxy表示代理类,第二个参数method表示需要代理的方法,第三个参数args表示代理方法的参数数组,第四个参数mp用 来去调用被代理对象方法

package com.demo;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MyInterceptor implements MethodInterceptor{    
    private Object target; ;//代理的目标对象
    public MyInterceptor(Object target) {
        this.target = target;
    } 
//proxy 在其上调用方法的代理实例    method拦截的方法    args  拦截的参数
 //invocation 用来去调用被代理对象方法
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, 
                                         MethodProxy invocation) throws Throwable {
        //1.记录日志 2.时间统计开始   3.安全检查
        Object retVal = invocation.invoke(target, args);  
        //4.时间统计结束
        return retVal;   
    }
//创建代理对象的方法
    public Object proxy(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();//该类用于生成代理类      
        enhancer.setSuperclass(this.target.getClass());//设置父类
        enhancer.setCallback(this);//设置回调用对象为本身
        return enhancer.create();

   }
}

上一篇下一篇

猜你喜欢

热点阅读