天天看点

代理模式(静态代理和动态代理原理分析)控制对象访问权限动态代理

控制对象访问权限

  • 概念
  • 类图
  • 代码实例
  • 和装饰者区别

概念

为其他对象提供一种代理以控制这个对象的访问,在某些情况下一个对象不能直接访问那个对象时,代理就起到了客户端和被代理对象(委托类)中介作用。 代理类和委托类都有同样接口。

好处:可以不用动原来类的逻辑,再次增加一些功能,符合开闭原则。真正的业务还是交给被代理对象处理的,因此在其委托被代理对象处理业务前后实现一些公共逻辑服务,例如加入缓存或日志等功能,无须修改原来的类就可以使用代理进行实现。

类图

代理模式(静态代理和动态代理原理分析)控制对象访问权限动态代理

Subject: 代理类和被代理类实现同样的接口

Proxy:代理类,里面有被代理类,具体逻辑委托被代理类进行处理

RealSubject:被代理类,可以在其内做一些访问权限控制,额外的业务处理

Client:看到的是代理类,并不知道具体处理业务逻辑的类,降低耦合性

代码实例

UserDAO 代理和被代理的公共的接口(Subject)

/**
 * @author duanyimiao
 * @create 2018-09-22 10:47 AM
 * @description 用户数据持久化逻辑接口
 **/
public interface UserDAO {

    boolean insert(String name,int age);
}
                

UserDAOImpl 被代理类(RealSubject)

/**
 * @author duanyimiao
 * @create 2018-09-22 10:47 AM
 * @description 用户数据持久具体实现
 **/
public class UserDAOImpl implements UserDAO {

    @Override
    public boolean insert(String name, int age) {
        System.out.println("insert to database name="+name +" age="+age);
        return true;
    }
}
                

UserDAOProxyByInterface 代理类,通过实现接口方式实现代理方式(Proxy)

/**
 * @author duanyimiao
 * @create 2018-09-22 10:50 AM
 * @description 用户持久数据的代理类(和被代理类实现同个接口方式)
 **/
public class UserDAOProxyByInterface implements UserDAO {
    private UserDAOImpl conreteUserDAO;

    public UserDAOProxyByInterface() {

    }
    public UserDAOProxyByInterface(UserDAOImpl conreteUserDAO) {
        this.conreteUserDAO = conreteUserDAO;
    }
    @Override
    public boolean insert(String name, int age) {
        System.out.println("before insert handle some logic by interface");
        return conreteUserDAO.insert(name, age);
    }
}
                

UserDAOProxyByExtend 代理类,通过继承被代理类实现的代理方式(Proxy)

/**
 * @author duanyimiao
 * @create 2018-09-22 10:50 AM
 * @description 用户持久数据的代理类(继承被代理类方式)
 **/
public class UserDAOProxyByExtend extends UserDAOImpl {
    private UserDAOImpl conreteUserDAO;

    public UserDAOProxyByExtend() {

    }
    public UserDAOProxyByExtend(UserDAOImpl conreteUserDAO) {
        this.conreteUserDAO = conreteUserDAO;
    }
    @Override
    public boolean insert(String name, int age) {
        System.out.println("before insert handle some logic by extend");
        return conreteUserDAO.insert(name, age);
    }
}
                

Client 获取代理对象客户端(Client)

/**
 * @author duanyimiao
 * @create 2018-09-22 10:52 AM
 * @description
 **/
public class Client {
    public static void main(String[] args) {
        UserDAOImpl conreteUserDAO = new UserDAOImpl();
        UserDAOProxyByInterface userDAOProxyByInterface = new UserDAOProxyByInterface(conreteUserDAO);
        //和被代理类实现同个接口方式进行代理
        userDAOProxyByInterface.insert("dynamo", 18);

        //通过继承被代理类方式进行代理
        UserDAOProxyByExtend userDAOProxyByExtend = new UserDAOProxyByExtend(conreteUserDAO);
        userDAOProxyByExtend.insert("dynamo", 18);

    }
}
                

输出结果:

before insert handle some logic by interface
insert to database name=dynamo age=18
before insert handle some logic by extend
insert to database name=dynamo age=18
                

和装饰者模式区别

代理模式关注的是控制对对象的访问,一般具体的被代理对象对Client是不可见的,直接在创建代理对象时就创建了被代理对象,也就是编译时就确定了。 但是装饰者模式:更关注的是在一个对象方法上动态添加修饰逻辑,但是这些逻辑修饰在运行时才能确定的,通过构造方法传入具体的装饰者对象,执行时递归调用修饰对象的方法。

动态代理

静态代理和动态代理:

1、静态代理:代理类由程序员创建的然后编译成.class文件。但是其中缺点是,具有重复代码,灵活性不好,例如在执行接口A中所有方法之前加上日志逻辑,那么使用静态代理的话,在代理类中每个方法都得加,如果我想add* 开头方法加上一种逻辑,select* 开头方法加上另一种逻辑,那么就很难去实现和维护了,想解决以上困惑就要使用动态代理了。

2、动态代理:是在运行的时候,通过jvm中的反射进行动态创建对象,生成字节码对象(构造方法参数 InvocationHandler h类型),传入由我们实现InvocationHandler接口的对象,通过反射创建代理对象。 然后当调用代理对象的任何方法都会调用h中的 invoke(Object proxy,Method method,Object[] args)传入当前代理对象、当前调用的方法、方法参数值。

JDK动态代理实现原理

要求被代理类必须要实现接口,因为JDK动代理实现是通过实现接口方式来实现的。需要实现 InvocationHandler接口(在invoke方法中实现一些额外的逻辑,添加一些新功能),通过Proxy.newProxyInstance(ClassLoader classLoader,Class<?> interfaces,InvocationHandler h)。

实现步骤

1.定义一个接口ProxyObj

2.编写该接口I的实现类ProxyObjImpl

3.编写InvocationHandler接口的实现类InvokcationInvokeHandler,构造h类对象的时候可以把要代理的对象target传入,target完成实际的动作。在里面的invoke方法里编写自己想实现的逻辑,然后再调用实际要完成的动作就可以。

4.调用Proxy.newProxyInstance方法,传递的三个参数分别是代理类的类加载器(可以用Impl实例的getClass().getClassLoader())

、代理类要实现的接口列表(可以用Impl实例getClass().getInterfaces())、InvocationHandler实现类的实例。

这样就生成了 P r o x y 0 类 的 对 象 , 由 于 Proxy0类的对象,由于 Proxy0类的对象,由于Proxy0类实现了ProxyObj接口,所以可以将对象强制转型成ProxyObj。

再说一下Proxy.newProxyInstance方法的实际过程:

1.使用传入的InvocationHandler实例参数将Proxy类的h实例初始化,注意,如果传入空对象的话,会抛出空指针错误,即h不能为空。

2.运行时生成代理Class,即$Proxy0

3.利用上面动态生成的$Proxy0类,构造出该类的对象,并返回。

实现代码

ProxyObj 代理类和被代理类实现的公共接口

public interface ProxyObj {

 public  void setName(String name);
}
                

ProxyObjImpl 被代理类

public class ProxyObjImpl implements  ProxyObj,ProxyObj1{

  private String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    System.out.println("set name="+name);
    this.name = name;
  }

  @Override
  public void setAge(Integer age) {
    System.out.println("set age="+age);
  }
}
                

InvokcationInvokeHandler 实现InvocationHandler接口

public class InvokcationInvokeHandler implements InvocationHandler {
    //真实的对象
    private ProxyObj proxyPbj;

    public InvokcationInvokeHandler(ProxyObj proxy) {
        this.proxyPbj = proxy;
    }

    /**
     *
     * @param proxy jvm生成的动态代理对象 $Proxy0
     * @param method 当前代理对象调用的方法对象,是代理对象实现接口中的方法
     * @param args 调用对象传入的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before call set proxy" + proxy.getClass()+" method="+method+" args="+ Arrays.toString(args));
        method.invoke(proxyPbj, args);
        //((ProxyObj)proxy).setName("2"); 会导致invoke方法循环调用导致StackoverflowError
        return null;
    }
}
                

ProxyFactory 获取代理对象的工厂

public class ProxyFactory {

  //获取代理对象
  public static ProxyObj getProxy(ProxyObj proxyObj) {
    /**
     * loader 指定加载jvm运行时动态生成的代理对象的加载器
     *
     * interface 真实对象实现的所有接口
     *
     * h 实现InvocationHandler接口对象
     */
    return (ProxyObj) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
        proxyObj.getClass().getInterfaces(), new InvokcationInvokeHandler(proxyObj));
  }

  public static void main(String[] args) {
    ProxyFactory.getProxy(new ProxyObjImpl()).setName("hh");
  }
}
                

输出结果

before call set proxyclass com.sun.proxy.$Proxy0 method=public abstract void com.dynamo.proxy.dynamicproxy.jdk.ProxyObj.setName(java.lang.String) args=[hh]
set name=hh
                

流程图:

代理模式(静态代理和动态代理原理分析)控制对象访问权限动态代理

通过javap可以看到具体代理类为:

import java.lang.reflect.InvocationHandler;   
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;   
import java.lang.reflect.UndeclaredThrowableException;  
   
public final class $Proxy0 extends Proxy implements UserManager {  
    private static Method m1;  
    private static Method m0;  
    private static Method m3;  
    private static Method m2;  
  
    static {  
        try {  
            m1 = Class.forName("java.lang.Object").getMethod("equals",  
                    new Class[] { Class.forName("java.lang.Object") });  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
                    new Class[0]);  
            m3 = Class.forName("cn.edu.jlu.proxy.UserManager").getMethod("addUser",  
                    new Class[0]);  
            m2 = Class.forName("java.lang.Object").getMethod("toString",  
                    new Class[0]);  
        } catch (NoSuchMethodException nosuchmethodexception) {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        } catch (ClassNotFoundException classnotfoundexception) {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    }  
  
    public $Proxy0(InvocationHandler invocationhandler) {  
        super(invocationhandler);  
    }  
  
    @Override  
    public final boolean equals(Object obj) {  
        try {  
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))  
                    .booleanValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final int hashCode() {  
        try {  
            return ((Integer) super.h.invoke(this, m0, null)).intValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final String toString() {  
        try {  
            return (String) super.h.invoke(this, m2, null);  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public void addUser() {  
        try {  
            super.h.invoke(this, m3, null);  
            return;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
  
    }  
} 

                

为什么无论调用JDK的动态代理对象还是CGLIB的代理对象的toString方法会出现栈溢出?

通过阅读JDK中代理类的源码 $Proxy0 extends Proxy implements I1,I2 看到,其中该代理类通过反射获取到这么几种Method对象, Object类中的方法对象:m2 = Class.forName(“java.lang.Object”).getMethod(“toString”,new Class[0]);

除了toString,还有 equals 和 hashCode方法。

还有在Proxy.newProxInstance()传入的Class[] interfaces 所有接口中的方法。当这些方法调用的时候都会触发父类Proxy中的InvocationHandler对象中的invoke方法

((String)super.h.invoke(this, m2, null));

所以如果在 实现InvocationHandler对象中的invoke方法中 调用代理对象中的 toString hashCode equals 和 其中被代理类的方法时都会导致栈溢出。

从上述的流程和代码可以看到如果调用代理类中的toString equals hashCode 和实现被代理类方法时都会导致方法栈溢出。

CGLIB动态代理实现原理

CGLIB(Code Generation Library)实现动态代理,并不要求被代理类必须实现接口,底层采用asm字节码生成框架生成代理类字节码(该代理类继承了被代理类)。所以被代理类一定不能定义为final class并且对于final 方法不能被代理。

实现步骤

Ehancer enhancer = new Enhancer() //Enhancer为字节码增强器,很方便对类进行扩展
enhancer.setSuperClass(被代理类.class);
enhancer.setCallback(实现MethodInterceptor接口的对象)
enhancer.create()//返回代理对象,是被代理类的子类
           

MethodInterceptor接口的intercept方法

/**
*obj 代理对象
*method 委托类方法
*arg 方法参数
*MethodProxy 代理方法MethodProxy对象,每个方法都会对应有这样一个对象 
*通过methodProxy.invokeSuper(obj,arg)方法调用委托类的方法
*/
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy)
           

实现代码

Query 被代理类

/**
 * @author duanyimiao
 * @create 2018-09-22 11:12 AM
 * @description 被代理类
 **/
public class Query {

    public boolean query(String name){
        System.out.println("Query query"+name);
        return true;
    }

    /**
     * cglib 代理通过继承被代理类,所有final方法不能被重写,所以定义的final方法不能被代理
     * @param name
     * @return
     */
    public final  boolean query1(String name){
        System.out.println("Query query1"+name);
        return true;
    }
}
                

CglibProxy 方法拦截器

/**
 * @author duanyimiao
 * @create 2018-09-22 11:04 AM
 * @description 目标方法拦截,在进行具体业务逻辑前后做一些额外逻辑
 **/
public class CglibProxy implements MethodInterceptor {

    /**
     *cglib代理是通过继承被代理类的方式进行代理的
     *
     * @param o 目标实例对象(继承于传入的被代理类)
     * @param method 目标方法对象
     * @param args 方法参数
     * @param proxy 代理对象实例
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //o.toString o.equals o.hashCode方法调用都会导致方法栈溢出
        System.out.println("o="+o.getClass()+" method="+method+" args="+ Arrays.toString(args)+" proxy="+proxy);
        System.out.println("before call add extera logic");
        //调用父类(被代理类)的方法
        boolean result = ((Boolean) proxy.invokeSuper(o,args)).booleanValue();
        System.out.println("after call add extera logic");
        return result;
    }
}
                

CglibProxyFactory 产生代理对象的工厂

/**
 * @author duanyimiao
 * @create 2018-09-22 11:04 AM
 * @description
 **/
public class CglibProxyFactory {
    private Enhancer enhancer = new Enhancer();
private CglibProxy cglibProxy = new CglibProxy();
    public Object getProxyObject(Class cls) {
        enhancer.setSuperclass(cls);
        enhancer.setCallback(cglibProxy);
        return enhancer.create();
    }
}
                

Client 获取代理对象的Client

/**
 * @author duanyimiao
 * @create 2018-09-22 11:18 AM
 * @description
 **/
public class Client {
    public static void main(String[] args) {
        CglibProxyFactory cglibProxyFactory = new CglibProxyFactory();
        Query query = (Query)cglibProxyFactory.getProxyObject(Query.class);
        query.query("dynamo");
        //该方法不能进过代理对象,因为query1方法定义为final,因此不能被代理类重写,因此直接调用被代理类的query1方法
        query.query1("dynamo1");
    }
}
                

流程图

代理模式(静态代理和动态代理原理分析)控制对象访问权限动态代理

cglib动态生成的代理类

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class HelloServiceImpl$$EnhancerByCGLIB$$82ef2d06
  extends HelloServiceImpl
  implements Factory
{
  private boolean CGLIB$BOUND;
  private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
  private static final Callback[] CGLIB$STATIC_CALLBACKS;
  private MethodInterceptor CGLIB$CALLBACK_0;
  private static final Method CGLIB$sayHello$0$Method;
  private static final MethodProxy CGLIB$sayHello$0$Proxy;
  private static final Object[] CGLIB$emptyArgs;
  private static final Method CGLIB$finalize$1$Method;
  private static final MethodProxy CGLIB$finalize$1$Proxy;
  private static final Method CGLIB$equals$2$Method;
  private static final MethodProxy CGLIB$equals$2$Proxy;
  private static final Method CGLIB$toString$3$Method;
  private static final MethodProxy CGLIB$toString$3$Proxy;
  private static final Method CGLIB$hashCode$4$Method;
  private static final MethodProxy CGLIB$hashCode$4$Proxy;
  private static final Method CGLIB$clone$5$Method;
  private static final MethodProxy CGLIB$clone$5$Proxy;
  
  static void CGLIB$STATICHOOK1()
  {
    CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    CGLIB$emptyArgs = new Object[0];
    Class localClass1 = Class.forName("proxy.HelloServiceImpl$$EnhancerByCGLIB$$82ef2d06");
    Class localClass2;
    Method[] tmp95_92 = ReflectUtils.findMethods(new String[] { "finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (localClass2 = Class.forName("java.lang.Object")).getDeclaredMethods());
    CGLIB$finalize$1$Method = tmp95_92[0];
    CGLIB$finalize$1$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "finalize", "CGLIB$finalize$1");
    Method[] tmp115_95 = tmp95_92;
    CGLIB$equals$2$Method = tmp115_95[1];
    CGLIB$equals$2$Proxy = MethodProxy.create(localClass2, localClass1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
    Method[] tmp135_115 = tmp115_95;
    CGLIB$toString$3$Method = tmp135_115[2];
    CGLIB$toString$3$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
    Method[] tmp155_135 = tmp135_115;
    CGLIB$hashCode$4$Method = tmp155_135[3];
    CGLIB$hashCode$4$Proxy = MethodProxy.create(localClass2, localClass1, "()I", "hashCode", "CGLIB$hashCode$4");
    Method[] tmp175_155 = tmp155_135;
    CGLIB$clone$5$Method = tmp175_155[4];
    CGLIB$clone$5$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
    tmp175_155;
    Method[] tmp223_220 = ReflectUtils.findMethods(new String[] { "sayHello", "()V" }, (localClass2 = Class.forName("proxy.HelloServiceImpl")).getDeclaredMethods());
    CGLIB$sayHello$0$Method = tmp223_220[0];
    CGLIB$sayHello$0$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "sayHello", "CGLIB$sayHello$0");
    tmp223_220;
    return;
  }
  
  final void CGLIB$sayHello$0()
  {
    super.sayHello();
  }
  
 	public final void sayHello()
	  {
	    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
	    if (tmp4_1 == null)
	    {
	      tmp4_1;
	      CGLIB$BIND_CALLBACKS(this);
	    }
	    if (this.CGLIB$CALLBACK_0 != null) {
	     tmp17_14.intercept(this, CGLIB$sayHello$3$Method, CGLIB$emptyArgs, CGLIB$sayHello$3$Proxy);
	    }
	    super.sayHello();
	  }
  
  final void CGLIB$finalize$1()
    throws Throwable
  {
    super.finalize();
  }
  
  protected final void finalize()
    throws Throwable
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    if (this.CGLIB$CALLBACK_0 != null) {
      return;
    }
    super.finalize();
  }
  
  final boolean CGLIB$equals$2(Object paramObject)
  {
    return super.equals(paramObject);
  }
  
  public final boolean equals(Object paramObject)
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null)
    {
      Object tmp41_36 = tmp17_14.intercept(this, CGLIB$equals$2$Method, new Object[] { paramObject }, CGLIB$equals$2$Proxy);
      tmp41_36;
      return tmp41_36 == null ? false : ((Boolean)tmp41_36).booleanValue();
    }
    return super.equals(paramObject);
  }
  
  final String CGLIB$toString$3()
  {
    return super.toString();
  }
  
  public final String toString()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null) {
      return (String)tmp17_14.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy);
    }
    return super.toString();
  }
  
  final int CGLIB$hashCode$4()
  {
    return super.hashCode();
  }
  
  public final int hashCode()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null)
    {
      Object tmp36_31 = tmp17_14.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
      tmp36_31;
      return tmp36_31 == null ? 0 : ((Number)tmp36_31).intValue();
    }
    return super.hashCode();
  }
  
  final Object CGLIB$clone$5()
    throws CloneNotSupportedException
  {
    return super.clone();
  }
  
  protected final Object clone()
    throws CloneNotSupportedException
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null) {
      return tmp17_14.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy);
    }
    return super.clone();
  }
  
  public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature)
  {
    String tmp4_1 = paramSignature.toString();
    switch (tmp4_1.hashCode())
    {
    case -1574182249: 
      if (tmp4_1.equals("finalize()V")) {
        return CGLIB$finalize$1$Proxy;
      }
      break;
    }
  }
  
  public HelloServiceImpl$$EnhancerByCGLIB$$82ef2d06()
  {
    CGLIB$BIND_CALLBACKS(this);
  }
  
  public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback)
  {
    CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback);
  }
  
  public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback)
  {
    CGLIB$STATIC_CALLBACKS = paramArrayOfCallback;
  }
  
  private static final void CGLIB$BIND_CALLBACKS(Object paramObject)
  {
    82ef2d06 local82ef2d06 = (82ef2d06)paramObject;
    if (!local82ef2d06.CGLIB$BOUND)
    {
      local82ef2d06.CGLIB$BOUND = true;
      Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get();
      if (tmp23_20 == null)
      {
        tmp23_20;
        CGLIB$STATIC_CALLBACKS;
      }
      local82ef2d06.CGLIB$CALLBACK_0 = (// INTERNAL ERROR //
                

其中该代理会实现所有被代理类非final的方法,并且每个方法有两种形式:例如被代理类有sayHello()方法,那么代理类会有两个该方法

final void CGLIB$sayHello$0()//该方法是通过在MethodInterceptor对象中methodProxy.invokeSuper(obj,args)进行调用的
  {
    super.sayHello();
  }

public final void sayHello()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    if (this.CGLIB$CALLBACK_0 != null) {
     tmp17_14.intercept(this, CGLIB$sayHello$3$Method, CGLIB$emptyArgs, CGLIB$sayHello$3$Proxy);
    }
    super.sayHello();
  }
           

一个是重写了父类的sayHello方法,如果callback不为null就会调用 其中实现MethodInterprector接口的对象的invoke方法。

实现MethodInterceptor接口的实例的intercept方法

@Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //o.toString o.equals o.hashCode方法调用都会导致方法栈溢出
        System.out.println("o="+o.getClass()+" method="+method+" args="+ Arrays.toString(args)+" proxy="+proxy);
        System.out.println("before call add extera logic");
        //调用父类(被代理类)的方法
        boolean result = ((Boolean) proxy.invokeSuper(o,args)).booleanValue();
        System.out.println("after call add extera logic");
        return result;
    }
                

代理类为每个委托方法都会生成两个方法

代理模式(静态代理和动态代理原理分析)控制对象访问权限动态代理

其中如果想要调用被代理类中的方法就需要使用 methodProxy.invokeSuper(obj,arg) 其中每个父类中非final的方法都会对应一个MethodProxy对象,下面看看其中该类中的invokeSuper方法:

代理模式(静态代理和动态代理原理分析)控制对象访问权限动态代理

和JDK动态代理最大区别就是,JDK是通过反射进行调用被代理对象的方法,而cglib是直接对被代理方法进行调用的。 通过类FastClassInfo存放了该被代理类和代理类对象,f1指向委托类对象,f2指向代理类对象,i1和i2分别代表着sayHello方法以及CGLIB$sayHello$0方法在类信息数组中的下标。其中

代理模式(静态代理和动态代理原理分析)控制对象访问权限动态代理

FastClass对Class对象进行特别的处理,比如将会用数组保存method的引用,每次调用方法的时候都是通过一个index下标来进行对类中某个方法调用。其中FastClassInfo中的f1、f2 i1、i2通过init方法进行初始化的,i1 和 i2是通过MethodProxy的getIndex方法就是通过方法签名来获得方法在存储了Class信息的数组中的下标。

代理模式(静态代理和动态代理原理分析)控制对象访问权限动态代理

从上面的源码分析可以看到invokeSuper方法调用实际上就是调用代理类的CGLIB$sayHello$0()方法然后该方法又调用其父类的sayHello方法。

代理方式

1、远程代理

例如:客户端有个接口A 里面有多种方法,客户端想和通过接口A和服务端通讯,给服务端发送请求。客户端并不需要知道实现A接口具体实现,只管调用就行,和请求本地接口一样。 这里A接口的实现就可以看作访问服务端的代理。这个代理就帮你发送请求了,并获取结果吐给客户端。

2、虚拟代理

例如浏览器加载大图片时会很慢,加载文字就很快。所以通过虚拟代理进行优化,代理对象会记录下图片的url和尺寸,然后一并返回未加载出来图片,等到访问到该图片的位置再去请求该页面。这个时候就不会出现下面的加载很快的文字一直等待上面图片加载出来才显示。

3、安全代理

在访问具体对象的时候做一些权限的校验,这样更好的控制对象的访问。

4、智能指引

在访问真实对象时候做一些额外逻辑处理,例如记录对象访问次数和引用次数,该对象第一次访问加入缓存中,在访问一个实际对象前,检查是否已经锁定它。

继续阅读