java代理的深入浅出(一)-Proxy

java代理的深入浅出(一)-Proxy

1.什么是代理

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。
静态代理:
由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
实现方式:
1、为每个代理类,写对应的代理类

 优点:简单方便
 缺点:当业务系统中需要大量的代理类时, 定义繁多的代理类

2、使用Aspectj

 使用Aspectj工具,将目标类class类,织入横切逻辑
 优点:因在JVM加载类前,已经将横切的业务逻辑加载到目标类中, 所以在执行效率上非常高
 缺点:不易维护, 修改的话, 还需要重新生成,编译 

动态代理:在程序运行时,运用反射机制动态创建而成。
优点:易修改,易维护
缺点:需要动态生成代理类, 在效率上比静态代理相对低

实现的两种方式
1、JDK动态代理
目标对象必须有对应接口定义
2、CGLIB动态代理
目标对象不用有对应接口, 会生成目标类的子类,所以目标类的方法不能是final

Spring AOP实现机制是动态代理, 主要是上面两种方式JDK、CGLIB

2.基本原理

目前Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。 其实现主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。 Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现。

Proxy类:

Porxy类也是在java.lang.reflect,Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

代理类具用以下属性:

  • 代理类是公共的、最终的,而不是抽象的。

  • 未指定代理类的非限定名称。但是,以字符串 "$Proxy" 开头的类名空间应该为代理类保留。

  • 代理类扩展 java.lang.reflect.Proxy。

  • 代理类会按同一顺序准确地实现其创建时指定的接口。

  • 如果代理类实现了非公共接口,那么它将在与该接口相同的包中定义。否则,代理类的包也是未指定的。注意,包密封将不阻止代理类在运行时在特定包中的成功定义,也不会阻止相同类加载器和带有特定签名的包所定义的类。

  • 由于代理类将实现所有在其创建时指定的接口,所以对其 Class 对象调用 getInterfaces 将返回一个包含相同接口列表的数组(按其创建时指定的顺序),对其 Class 对象调用 getMethods 将返回一个包括这些接口中所有方法的 Method 对象的数组,并且调用 getMethod 将会在代理接口中找到期望的一些方法。

  • 如果 Proxy.isProxyClass 方法传递代理类(由 Proxy.getProxyClass 返回的类,或由 Proxy.newProxyInstance 返回的对象的类),则该方法返回 true,否则返回 false。

  • 代理类的 java.security.ProtectionDomain 与由引导类加载器(如 java.lang.Object)加载的系统类相同,原因是代理类的代码由受信任的系统代码生成。此保护域通常被授予 java.security.AllPermission。

  • 每个代理类都有一个可以带一个参数(接口 InvocationHandler 的实现)的公共构造方法,用于设置代理实例的调用处理程序。并非必须使用反射 API 才能访问公共构造方法,通过调用 Proxy.newInstance 方法(将调用 Proxy.getProxyClass 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。

      protected  Proxy(InvocationHandler h)  //使用其调用处理程序的指定值从子类(通常为动态代理类)构建新的 Proxy 实例。 
      
      
      static InvocationHandler getInvocationHandler(Object proxy) //返回指定代理实例的调用处理程序。 
      
      
      static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) //返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。 
      
      
      static boolean isProxyClass(Class<?> cl) //当且仅当指定的类通过 getProxyClass 方法或 newProxyInstance 方法动态生成为代理类时,返回 true。 
      
      
      static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) //返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
    

InvocationHandler接口:

InvocationHandler接口也是在java.lang.reflect,唯一的一个方法是invoke如下:

Object invoke(Object proxy, Method method, Object[] args)

这个方法有三个参数,其中第二和第三个参数都比较好理解,一个是被拦截的方法,一个是该方法的参数列表。关键是第一个参数。按照doc文档的解析,proxy - the proxy instance that the method was invoked on也就是说,proxy应该是一个代理实例(动态代理类)。

3.示例

接口与实现类:

public interface UserService {

    void addUser(long cardId);
}

public class UserServiceImpl implements UserService {
    public void addUser(long cardId) {
        System.out.println("cardId>>>>>"+cardId);
    }
}

代理类的创建和拦截处理类

public class UserInvacationHandler implements InvocationHandler {

    private Object target;
     public Object getProxyInstance(Object target){
         this.target =target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        System.out.println("before target method.....");
        result = method.invoke(target,args);
        System.out.println("after target method.....");
        return result;
    }
}

代理测试类

public class ProxyTest {
    public static void main(String[] args){
        UserInvacationHandler userInvacationHandler = new UserInvacationHandler();
        UserService userService = (UserService) userInvacationHandler.getProxyInstance(new UserServiceImpl());
        userService.addUser(1L);
    }
}

代理类反编译

生成代理类的方法Proxy.newProxyInstance(), 其源码核心代码是ProxyGenerator.generateProxyClass(String paramString, Class[] paramArrayOfClass)

public class ProxyClassFile {

    public static void main(String[] args){

        String proxyName = "UserServiceProxy";

        UserService a = new UserServiceImpl();
        Class[] interfaces =  a.getClass().getInterfaces();
        byte[] bytes = ProxyGenerator.generateProxyClass(proxyName, interfaces);
        File f  = new File("D:/work/code/middleware/study/proxy/UserServiceProxy.class");
        try{
            FileOutputStream fos = new FileOutputStream(f);
            fos.write(bytes);
            fos.flush();
            fos.close();
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }catch(IOException e1){
            e1.printStackTrace();
        }


    }
}

反编译

import com.longchao.proxy.UserService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class UserServiceProxy extends Proxy
  implements UserService
{
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;

  public UserServiceProxy(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 void addUser(long paramLong)
    throws 
  {
    try
    {
      this.h.invoke(this, m3, new Object[] { Long.valueOf(paramLong) });
      return;
    }
    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 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") });
      m3 = Class.forName("com.longchao.proxy.UserService").getMethod("addUser", new Class[] { Long.TYPE });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      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());
  }
}

从源码发现, addUser方法(或其他方法)都会调用this.h.invoke(this, m3, null);
this.h 是其父类Proxy的protected InvocationHandler h; 即我们自定义的UserInvocationHandler,

m3:
m3 = Class.forName("com.user.UserService").getMethod("addUser", new Class[0]);

4.总结

一个典型的动态代理创建对象过程可分为以下四个步骤:

  • 1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);

  • 2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
    Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});

  • 3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
    Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});

  • 4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
    Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
    为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
    生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))

5美中不足

诚然,Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。

原文地址:https://www.cnblogs.com/zhulongchao/p/5495071.html