Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

Proxy 动态代理 InvocationHandler CGLIB MD


目录

InvocationHandler 接口

  1. java.lang.reflect.InvocationHandler

InvocationHandler is the interface implemented by the invocation handler of a proxy instance.

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。

定义的方法:

  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

Processes a method invocation on a proxy instance and returns the result. This method will be invoked on an invocation handler when a method is invoked on a proxy instance that it is associated with.

在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。

参数:

  • proxy - the proxy instance that the method was invoked on

    在其上调用方法的代理实例

  • method - the Method instance corresponding to the interface method invoked on the proxy instance.

    对应于在代理实例上调用的接口方法的 Method 实例。

  • args - an array of objects containing the values of the arguments passed in the method invocation on the proxy instance, or null if interface method takes no arguments.

    包含传入代理实例方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。

返回值:

the value to return from the method invocation on the proxy instance.

从代理实例的方法调用返回的值。

Proxy 代理类

  1. public class java.lang.reflect.Proxy extends Object implements java.io.Serializable

简介

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

To create a proxy for some interface Foo:

  1. InvocationHandler handler = new MyInvocationHandler(new FooImpl());//FooImpl是实现Foo接口的委托类
  2. Foo f = (Foo) Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class })
  3. .getConstructor(new Class[] { InvocationHandler.class })
  4. .newInstance(new Object[] { handler });

or more simply:

  1. Foo proxy = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),//定义了由哪个ClassLoader对象来对生成的代理对象进行加载
  2. new Class[] { Foo.class },//表示的是我将要给我需要代理的对象提供一组什么接口,之后我这个代理对象就会实现了这组接口
  3. handler);//表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

A dynamic proxy class is a class that implements a list of interfaces specified at runtime when the class is created, with behavior as described below.

  • A proxy interface is such an interface that is implemented by a proxy class.
  • A proxy instance is an instance of a proxy class.
  • Each proxy instance has an associated invocation handler object, which implements the interface InvocationHandler.
  • A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance, a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments.
  • The invocation handler processes the encoded method invocation as appropriate and the result that it returns will be returned as the result of the method invocation on the proxy instance.

代理类具有的属性

  • 代理类是 public, final, 并且不是 abstract.

    System.out.println(Modifier.toString(proxy.getClass().getModifiers()));//final

    System.out.println(Modifier.toString(Proxy.class.getModifiers()));//public

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

    System.out.println(proxy.getClass().getName());//【$Proxy0】

  • 代理类都 extends 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 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。

代理实例具有的属性

  • Given a 代理实例 proxy and one of the interfaces implemented by its 代理类 Foo, 表达式 proxy instanceof Foo 将返回 true,并且 (Foo) proxy 的强制转换操作将会成功,而不抛出 ClassCastException。
  • Each proxy instance has an associated invocation handler, the one that was passed to its constructor. The static Proxy.getInvocationHandler method will return the invocation handler associated with the proxy instance passed as its argument.

    System.out.println(Proxy.getInvocationHandler(proxy) == handler);//true

  • An interface method invocation on a proxy instance will be encoded and dispatched to the invocation handler's invoke method as described in the documentation for that method.
  • An invocation of the hashCode, equals, or toString methods declared in java.lang.Object on a proxy instance will be encoded and dispatched to the invocation handler's invoke method in the same manner as interface method invocations are encoded and dispatched, as described above.

    重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。

  • The declaring class of the Method object passed to invoke will be java.lang.Object.
  • Other public methods of a proxy instance inherited from java.lang.Object are not overridden by a proxy class, so invocations of those methods behave like they do for instances of java.lang.Object.

在多代理接口中重复的方法

乱七八糟的,这个问题设计时最好规避。

API

字段

protected InvocationHandler h 此代理实例的调用处理程序。

构造方法

protected Proxy(InvocationHandler h) 从子类(通常是动态代理类)构造一个新的Proxy实例,并为其调用处理程序指定值。

公共方法

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

    返回值:一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口

    参数:

    • loader - 定义代理类的类加载器。定义了由哪个ClassLoader对象来对生成的代理对象进行加载
    • interfaces - 代理类要实现的接口列表。表示的是我将要给我需要代理的对象提供一组什么接口,之后我这个代理对象就会实现了这组接口
    • h - 指派方法调用的调用处理程序。表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

底层实现原理

关于JDK的动态代理,最为人熟知要可能要数Spring AOP的实现,默认情况下,Spring AOP的实现对于接口来说就是使用的JDK的动态代理来实现的,而对于的代理使用CGLIB来实现。

JDK从1.3开始支持动态代理。JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。

代理类继承了Proxy类,实现了代理的接口,由于java不能多继承,所以代理类不能再继承其他的类,所以JDK的动态代理不支持对类的代理,只支持对接口的代理。

在代理类所实现的接口方法的内部,其只是简单的调用了InvocationHandler的invoke方法,而没有调用委托类所实现的接口的方法,所以对使用者来说,其效果就是:委托类的接口方法被代理类所代理了(或者说拦截了)。

如果我们在InvocationHandler的invoke方法中进行一些特殊操作,甚至可以直接返回,这基本上就是AOP的一个简单实现了。当然通常我们的做法是,在invoke方法中通过反射调用目标对象的接口方法,并可以根据需要在目标对象的方法执行前后插入任何需要的逻辑以进行功能的增强。

CGLIB 简介

GitHub主页

WIKI

需要添加两个jar包:

CGLib 2.2

ASM 3.3.1

Byte Code Generation Library is high level API to generate and transform JAVA byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access.

JDK从1.3版本起就提供了一个动态代理,它使用起来非常简单,但是有个明显的缺点:需要目标对象实现一个或多个接口。使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。

cglib是一个功能强大,高性能的代码生成库,它简单易用,它的运行速度要远远快于JDK的动态代理。在实现内部,CGLIB库使用了ASM这一个轻量但高性能的字节码操作框架来转化字节码,产生新类。ASM使用了一个类似于SAX分析器的机制来达到高性能。PS:使用ASM需要对JVM非常了解,包括类文件格式和指令集。

CGLIB被广泛使用在基于代理的AOP框架提供方法拦截(例如 Spring AOP 和 dynaop)。Hibernate作为最流行的ORM工具也同样使用CGLIB库来代理单端关联。EasyMock和jMock作为流行的Java测试库,它们提供Mock对象的方式来支持测试,都使用了CGLIB来对没有接口的类进行代理。

cglib的原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。由于是通过创建子类来代理父类,因此不能代理被final修饰的类(代理final修饰的类会抛异常,代理final修饰的方法只会原样执行委托类的方法而不能做任何拦截)。

但是cglib有一个很致命的缺点:cglib的底层是采用著名的ASM字节码生成框架,使用字节码技术生成代理类,也就是通过操作字节码来生成的新的.class文件,而我们在android中加载的是优化后的.dex文件,也就是说我们需要可以动态生成.dex文件代理类,因此cglib在Android中是不能使用的。

2018-10-7

Proxy 动态代理 InvocationHandler CGLIB MD的更多相关文章

  1. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  2. 代理模式 & Java原生动态代理技术 & CGLib动态代理技术

    第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...

  3. 09Spring_AOP介绍和java本身的动态代理以及cglib代理

    Aspect Oriented Programming 面向切面编程 1. 业界 AOP 实际上 OOP (面向对象编程 ) 延伸 ----  OOP编程语言. AOP设计思想,下面给出一张AOP的设 ...

  4. Spring AOP详解 、 JDK动态代理、CGLib动态代理

    AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...

  5. 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

  6. JDK动态代理与CGLib动态代理相关问题

    导读: 1.JDK动态代理原理是什么?为什么不支持类的代理? 2.JDK动态代理实例 3.CGLib代理原理是什么? 4.CGLib代理实例 5.JDK动态代理与CGLib代理的区别是什么? 6.总结 ...

  7. jdk动态代理与cglib动态代理例子

    1.JAVA的动态代理特征:特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象 ...

  8. java动态代理之CGLIB实现

    动态代理(CGlib 与连接池的案例) Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用. 我们要使用cglib代理必须引入 cglib的jar包 ...

  9. 从静态代理,jdk动态代理到cglib动态代理-一文搞懂代理模式

    从代理模式到动态代理 代理模式是一种理论上非常简单,但是各种地方的实现往往却非常复杂.本文将从代理模式的基本概念出发,探讨代理模式在java领域的应用与实现.读完本文你将get到以下几点: 为什么需要 ...

随机推荐

  1. BZOJ4247 : 挂饰

    首先将挂饰按照挂钩个数从大到小排序,然后DP 设f[i][j]处理完前i个挂饰,还有j个多余挂钩的最大喜悦值,则 f[0][1]=0 f[i][j]=max(f[i-1][max(j-a[i],0)+ ...

  2. 吴恩达-coursera-机器学习-week2

    四.多变量线性回归(Linear Regression with Multiple Variables) 4.1 多维特征 4.2 多变量梯度下降 4.3 梯度下降法实践1-特征缩放 4.4 梯度下降 ...

  3. 一种高效的序列化方式——MessagePack

    最近在弄一些数据分析方面的内容,发现很多时候数据瓶颈在模块之间的数据序列化和反序列化上了,原来项目中用的是Json,找了一圈发现Json.net在Json序列化库中已经是性能的佼佼者了,便准备从序列化 ...

  4. STM32 TIMER DIAGRAM

  5. AES advanced encryption standard 3

    This optimized <../aesbench/> AES implementation conforms to FIPS-. aes.h #ifndef _AES_H #defi ...

  6. [Asp.net]web.config customErrors 如何设置?

    摘要 customErrors也经常在开发部署中看到<customErrors mode="Off" />,设置这样可以在页面上看到详细的错误信息.但也为黑客提供了攻击 ...

  7. 用Qemu搭建x86_64学习环境

    作者信息 作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 软件平台 主机: Ubuntu14.04 64位版本 模拟器:Qemu-2.8.0 Linux内核 ...

  8. Android 数据存储03之SQLite

    SQLite数据存储 Android 集成了 SQLite 数据库.它存储在 /data/data/< 项目文件夹 >/databases/ 下.Android 开发中使用 SQLite ...

  9. WordPress主题开发:开启侧边栏小工具功能

    步骤一:在主题的functions.php中,添加一段代码,开启侧边栏功能,代码如下: <?php //参数 $args = array( 'name' => __( '主侧边栏'), ' ...

  10. python测试开发django-24.表单提交之get请求

    前言 通常我们需要在html页面上输入框里面输入数据,比如登录的时候,输入账号和密码,点提交按钮. 从html把数据提交到服务端,服务端接收数据后判断提交的数据,然后做出对应的响应,这么一整个流程就是 ...