动态代理
一、什么是代理
代理是一种设计模式,属于结构型模式。提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此在目标实现工能的基础上,前后增加拦截实现额外的功能。
二、图型描述
代理可以分为静态代理和动态代理两类。
- 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的class文件已经被创建。
- 动态代理:在程序运行时通过反射机制动态创建的。
三、动态代理
JDK代理
动态代理是指动态的在内存中创建代理对象(需要指定要代理目标对象实现的接口类型),即利用JDK的API生成指定接口的对象,也称为JDK代理或接口代理。
JDK动态代理主要涉及两个类:java.lang.rellect.Proxy
和java.lang.reflect.InvocationHandler
。
下边摘抄自JDK 1.8API
-
Proxy
提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。为某个接口创建代理
Foo
:InvocationHandler handler = new MyInvocationHandler(...); Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class); Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class). newInstance(handler);
或更简单地:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[] { Foo.class }, handler);
动态代理类 (以下简称为代理类 )是一个实现在运行时创建指定的接口列表的实现类,具有如下所述的行为。 代理接口是由代理类实现的接口。 代理实例是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序对象,它实现了接口
InvocationHandler
。 通过其代理接口之一的代理实例上的方法调用将被分派到实例调用处理程序的invoke
方法,传递代理实例,java.lang.reflect.Method
被调用方法的java.lang.reflect.Method
对象以及包含参数的类型Object
Object的数组。 调用处理程序适当地处理编码方法调用,并且返回的结果将作为方法在代理实例上调用的结果返回。
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) | 构造实现指定接口的代理类的一个新实例,所有方法会调用给定处理器对象的 invoke 方法 |
-
InvocationHandler
InvocationHandler
是由代理实例的调用处理程序实现的接口 。每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的
invoke
方法。方法 注释 Object invoke(Object proxy, Method method, Object[] args) 处理代理实例上的方法调用并返回结果。当在与之关联的代理实例上调用方法时,将在调用处理程序中调用此方法。
CGLIB动态代理
引入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
使用示例
Object proxy = Enhancer.create(obj.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
/*增强逻辑*/
return null;
}
});
JDK代理和CGLIB代理区别
- JDK动态代理只能对实现了接口的类生成代理,而不能针对类
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法因为是继承,所以该类或方法最好不要声明成final