Spring AOP系列之---JDK动态代理

博客分类: 后台 阅读次数: *

Spring AOP系列之---JDK动态代理

为什么要创建代理

代理,顾名思义可以理解为真实目标和调用者之间的过程态,可以通过代理去操作目标类。可以说在整个spring框架中代理随处可见,那么使用代理的作用是什么呢?spring通过使用代理,可以更加灵活的凸显java面向对象的编程优势,通过动态代理,可以对目标类加入通知或者拦截器,从而可以提供切面功能,或者提供灵活的可配置的参数

public interface DoService {
    //添加
    public void  add();
    //查询
    public void selectInfo();
    //更新
    public void update();
}


public class DoServiceImpl implements DoService{

    //用户名
    private String userName;
    
    @Override
    public void add() {
        System.out.println("添加的方法");
        
    }

    @Override
    public void selectInfo() {
        System.out.println("查询的方法");
        
    }

    @Override
    public void update() {
        System.out.println("更新的方法");
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
    

}

比如上述代码提供了实现更新,添加,查询的接口DoService及其实现类DoServiceImpl。现在如果想对业务实现类中每个方法执行前加上打印日志的逻辑,那么在没用代理之前,只能在每个方法前手动把要新增的业务逻辑加上去。那么有了代理以后呢,这些要新增的操作,我们就可以在代理类中公共的地方去完成,而不用每个方法逐一添加。

JDK动态代理的创建过程

对于特定对象JDK代理实现主要包含三个步骤:1、创建业务接口及实现业务接口的实现类(目标类)。2、实现InvocationHandler接口类(实现创建代理类的方法),并且对接口中invoke方法进行重载,这个invoke方法将在后面生成的代理对象中每个方法体中被调用。3、根据目标类及实现的InvocationHandler类生成目标代理类Proxcy0。具体实例如下所示:

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

import cn.service.impl.DoServiceImpl;

/**
 * 代理工厂类
 * @author hyj
 *
 */
public class JDKProxyFactory implements InvocationHandler{
    //被代理的目标对象
   private Object obj;
   /**
    * 通过代理工厂的方式来创建代理类
    * @param obj  要代理的类的对象(该对象为Proxcy的子类)
    * @return
    */
   public Object createProxyIntance(Object obj){
       this.obj=obj;
       //第一个参数是目标对象的类加载器
       //第二个参数是目标对象实现的接口
       //第三个参数传入一个InvocationHandler实例,该参数和回调有关系。
       return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
       
   }
   //该invoke方法在生成的目标代理对象的方法体中被调用
   @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
       Object proxyObject=null;
       DoServiceImpl ds=(DoServiceImpl)obj;
       if(ds.getUserName()!=null){
           proxyObject= method.invoke(ds, args);
       }else{
           System.out.println("用户名为空,已拦截");
       }
        return proxyObject;
    }
    public Object getObj() {
        return obj;
    }
    public void setObj(Object obj) {
        this.obj = obj;
    }  
}

//测试类

import cn.aop.JDKProxyFactory;
import cn.service.DoService;
import cn.service.impl.DoServiceImpl;

public class TestHappy {
   public static void main(String[] args) {
      JDKProxyFactory jpf=new JDKProxyFactory();
      DoService ds=(DoService)jpf.createProxyIntance(new DoServiceImpl("fsf"));
      ds.selectInfo();
   }
}

生成的JDK动态代理对象长什么样?

通过研究源码可知,创建代理对象调用的是Proxcy中提供的方法。Proxcy对象是生成的代理对象的父类。Proxcy中有个InvocationHandler属性是proctect类型的,可以看出该属性就是提供给Proxcy子类使用的。下面是生成代理对象的源码。


public final class $Proxy11extends Proxy implements IStudent{

  private static Method m1;

  private static Method m0;

  private static Method m3;

  private static Method m2;

 

  public $Proxy11(InvocationHandler paramInvocationHandler) throws   {

    super(paramInvocationHandler);

  }

 

  public final boolean equals(Object paramObject) throws  {

    try {

      return ((Boolean)this.h.invoke(this, m1,new Object[] { paramObject })).booleanValue();

    } catch (RuntimeException localRuntimeException) {

      throw localRuntimeException;

    } catch (Throwable localThrowable) {

      throw new UndeclaredThrowableException(localThrowable);

    }

  }

  public final int hashCode() throws {

    try {

      return ((Integer)this.h.invoke(this, m0,null)).intValue();

    } catch (RuntimeException localRuntimeException) {

      throw localRuntimeException;

    } catch (Throwable localThrowable) {

      throw new UndeclaredThrowableException(localThrowable);

    }

  }

 

  public final void add(String paramString) throws {

    try  {

      this.h.invoke(this, m3, new Object[] { paramString });

      return;

    } catch (RuntimeException localRuntimeException)  {

      throw localRuntimeException;

    }  catch (Throwable localThrowable) {

      throw new UndeclaredThrowableException(localThrowable);

    }

  }

 //update selectInfo方法如上述add方法

  public final String toString()throws {

    try {

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

    }  catch (RuntimeException localRuntimeException) {

      throw localRuntimeException;

    }  catch (Throwable localThrowable)  {

      throw new UndeclaredThrowableException(localThrowable);

    }

  }
  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("spring_dynamic_proxy.IStudent").getMethod("say",new Class[] { Class.forName("java.lang.String") });

      m2 = Class.forName("java.lang.Object").getMethod("toString",new Class[0]);

      return;

    }  catch (NoSuchMethodException localNoSuchMethodException) {

      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());

    } catch (ClassNotFoundException localClassNotFoundException) {

      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());

    }

  }

}

通过代理对象的源码就看出来,为什么测试类中调用目标对象的方法就会触发InvocationHanler类中的invoke方法了吧。

JDK动态代理就先分析到这里

未完。。。。待续。。。。晚安