Java基础干货动态代理核心代码

Posted 在路上的德尔菲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础干货动态代理核心代码相关的知识,希望对你有一定的参考价值。

JDK动态代理


//自定义的接口类,JDK动态代理的实现必须有对应的接口类
public interface ExInterface {
    void execute();
}

//A类,实现了ExInterface接口类
public class A implements ExInterface{
    public void execute(){
        System.out.println("执行A的execute方法...");
    }
}
//代理类的实现
public class JDKProxy implements InvocationHandler{

    /**
     * 要被代理的目标对象
     */
    private A target;

    public JDKProxy(A target){
        this.target=target;
    }

        /*
         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 第一个参数
         * handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
         * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,
         * 表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 第三个参数handler, 我们这里将这个代理对象关联到了上方的
         * InvocationHandler 这个对象上
         */
    public ExInterface createProxy(){
        return (ExInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    /**
     * 调用被代理类(目标对象)的任意方法都会触发invoke方法
     * @param proxy 代理类
     * @param method 被代理类的方法
     * @param args 被代理类的方法参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //过滤不需要该业务的方法
        if("execute".equals(method.getName())) {
            //调用前验证权限
            AuthCheck.authCheck();
            //调用目标对象的方法
            Object result = method.invoke(target, args);
            //记录日志数据
            Report.recordLog();
            return result;
        }eles if("delete".equals(method.getName())){
            //.....
        }
        //如果不需要增强直接执行原方法
        return method.invoke(target,args);
    }
}

 //测试验证
 public static void main(String args[]){
      A a=new A();
      //创建JDK代理
      JDKProxy jdkProxy = new JDKProxy(a);
      //创建代理对象
      //proxy.getClass().getName()为com.sun.proxy.$Proxy0格式
      
      ExInterface proxy = jdkProxy.createProxy();
      //执行代理对象方法
      proxy.execute();
  }

核心类是java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler,都是反射包里面的。
注意通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,JDK中有个规范,只要要是$开头的.class文件,一般都是自动生成的并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。

JDK动态代理原理

JDK采用字节重组,重新生成对象来替代原始对象,以达到动态代理的目的,JDK动态代理生成对象的步骤如下:

  1. 拿到被代理对象的引用,然后获取他的接口 (Proxy.getInstance方法) ,反射获取
  2. JDK代理重新生成一个类,同时该类实现我们给的代理对象所实现的接口
  3. 动态生成java代码,新加的业务逻辑方法由一定的逻辑代码调用(在代码中体现)
  4. 编译新生成java代码的class文件
  5. 重新加载到JVM中运行

cglib动态代理

//被代理的类即目标对象
public class A {
    public void execute(){
        System.out.println("执行A的execute方法...");
    }
}

//代理类
public class CGLibProxy implements MethodInterceptor {

    /**
     * 被代理的目标类
     */
    private A target;

    public CGLibProxy(A target) {
        super();
        this.target = target;
    }

    /**
     * 创建代理对象
     * @return
     */
    public A createProxy(){
        // 使用CGLIB生成代理:
        // 1.声明增强类实例,用于生产代理类
        Enhancer enhancer = new Enhancer();
        // 2.设置被代理类字节码,CGLIB根据字节码生成被代理类的子类
        enhancer.setSuperclass(target.getClass());
        // 3.//设置回调函数,即一个方法拦截
        enhancer.setCallback(this);
        // 4.创建代理:
        return (A) enhancer.create();
    }

    /**
     * 回调函数
     * @param proxy 代理对象
     * @param method 委托类方法
     * @param args 方法参数
     * @param methodProxy 每个被代理的方法都对应一个MethodProxy对象,
     *                    methodProxy.invokeSuper方法最终调用委托类(目标类)的原始方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   //过滤不需要该业务的方法
      if("execute".equals(method.getName())) {
          //调用前验证权限(动态添加其他要执行业务)
          AuthCheck.authCheck();

          //调用目标对象的方法(执行A对象即被代理对象的execute方法)
          Object result = methodProxy.invokeSuper(proxy, args);

          //记录日志数据(动态添加其他要执行业务)
          Report.recordLog();

          return result;
      }else if("delete".equals(method.getName())){
          //.....
          return methodProxy.invokeSuper(proxy, args);
      }
      //如果不需要增强直接执行原方法
      return methodProxy.invokeSuper(proxy, args);

    }
}

作者:极乐君
链接:https://zhuanlan.zhihu.com/p/25522841
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

详细:https://www.cnblogs.com/duanxz/archive/2012/12/03/2799504.html

以上是关于Java基础干货动态代理核心代码的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点# 设计模式之代理模式:动态代理

百度T7:深入理解Java动态代理与代码模拟JDK实现动态代理JAVA核心

Java基础加强——动态代理

Java动态代理代码快速上手

学习Spring必学的Java基础知识----动态代理

Java动态代理