Java 代理之JDK动态代理

用到的两个类, java.lang.reflect.InvocationHandler java.lang.reflect.Proxy

示例

UserService.java

package cn.cecurio.proxy.dynamic.jdk;

/**
 * @author: Cecurio
 * @create: 2018-02-25 16:20
 **/
public interface UserService {
    void add();
    void update();
}

UserServiceImpl.java 委托类

package cn.cecurio.proxy.dynamic.jdk;

/**
 * @author: Cecurio
 * @create: 2018-02-25 16:22
 **/
public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("UserServiceImpl.add()");
    }

    public void update() {
        System.out.println("UserServiceImpl.update()");
    }
}

ServiceInvocationHandler.java


package cn.cecurio.proxy.dynamic.jdk;

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

/**
 * @author: Cecurio
 * @create: 2018-02-25 16:24
 **/
public class ServiceInvocationHandler implements InvocationHandler {

    private Object target;

    public ServiceInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 创建代理实例
     *
     * @return
     * @throws Throwable
     */
    public Object getProxy() throws Throwable {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
         target.getClass().getInterfaces(), 
         this);
    }

    /**
     * 实现 InvocationHandler 接口, 必须实现invoke方法
     * 执行目标对象的方法, 并进行增强
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        System.out.println("代理方法开始");

        System.out.println("被代理的方法是:" + method);
        // 执行目标对象的方法
        result = method.invoke(target, args);

        System.out.println("代理方法结束");

        return result;
    }
}

JdkProxyTest.java 测试类

package cn.cecurio.proxy.dynamic.jdk;

/**
 * @author: Cecurio
 * @create: 2018-02-25 16:42
 **/
public class JdkProxyTest {
    public static void main(String[] args) throws Throwable {
        UserService userService = new UserServiceImpl();
        ServiceInvocationHandler handler = new ServiceInvocationHandler(userService);

        UserService userServiceProxy = (UserService) handler.getProxy();

        userServiceProxy.add();
    }
}

执行结果

代理方法开始
被代理的方法是:public abstract void cn.cecurio.proxy.dynamic.jdk.UserService.add()
UserServiceImpl.add()
代理方法结束

JDK动态代理的用法:

  1. 一个接口
  2. 一个接口的实现类, 用作委托类
  3. 一个实现 java.lang.reflect.InvocationHandler 的类, 这个类有个成员变量(上面的接口实现类), 此类必须实现invoke(Object proxy, Method method, Object[] args)方法
  4. 必须要有创建代理类的操作, 是上述代码的UserService userServiceProxy = (UserService) handler.getProxy();的部分, 生成的代理类继承Proxy, 实现委托类实现的接口

代理类的字节码是从哪里生成的?

进入java.lang.reflect.Proxy.ProxyClassFactory#apply()方法,最终是通过调用sun.misc.ProxyGenerator#generateProxyClass(final String proxyName, Class<?>[] interfaces, int accessFlags)方法生成byte[],然后调用方法java.lang.reflect.Proxy#defineClass0,由类加载器加载生成对应的Class对象

到底生成了怎样的字节码? 我们可以自己调用sun.misc.ProxyGenerator#generateProxyClass(final String proxyName, Class<?>[] interfaces, int accessFlags) 这个方法去生成代理类的字节码,然后反编译看看

package cn.cecurio.proxy;

import sun.misc.ProxyGenerator;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

interface Service {
    void add(String username,String password);
    void update(String username,String password);
}

/**
 * @author: Cecurio
 * @create: 2018-04-07 2:11
 **/
public class ProxyGeneratorTest {

    public static void main(String[] args) {
        String name = "ProxyService";
        byte[] data = ProxyGenerator.generateProxyClass(name, new Class[]{Service.class});
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(name + ".class");
            out.write(data);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

动态生成的Service的实现类反编译后内容如下

import cn.cecurio.proxy.Service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class ProxyService
  extends Proxy
  implements Service
{
  private static Method m1;
  private static Method m3;
  private static Method m4;
  private static Method m2;
  private static Method m0;
  
  public ProxyService(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void add(String paramString1, String paramString2)
  {
    try
    {
      this.h.invoke(this, m3, new Object[] { paramString1, paramString2 });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void update(String paramString1, String paramString2)
  {
    try
    {
      this.h.invoke(this, m4, new Object[] { paramString1, paramString2 });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("cn.cecurio.proxy.Service").getMethod("add", new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") });
      m4 = Class.forName("cn.cecurio.proxy.Service").getMethod("update", new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

看到生成的构造函数需要一个InvocationHandler的实例,这个实例是怎么传递给ProxyService的构造函数的呢?是通过java.lang.reflect.Proxy#newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)这个方法,具体代码如下:

// cl是代理生成的Class对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
    AccessController.doPrivileged(new PrivilegedAction<Void>() {
        public Void run() {
            cons.setAccessible(true);
            return null;
        }
    });
}
// 通过反射生成代理类的实例
return cons.newInstance(new Object[]{h});

Service接口的每个方法实现里都有类似下面的代码

this.h.invoke(this, m4, new Object[] { paramString1, paramString2 });

总结

JDK动态代理只做了两件事:

  1. Look up or generate the designated proxy class.(查找或生成指定的代理类)
  2. Invoke its constructor with the designated invocation handler.(使用指定的调用处理程序调用它的构造函数)

参考文章

http://blog.csdn.net/jiankunking/article/details/52143504

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值