0%

18.5.1使用Proxy和InvocationHandler创建动态代理

18.5.1使用Proxy和InvocationHandler创建动态代理

Javajava.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类或动态代理对象
Proxy提供了用于创建动态代理类代理对象的静态方法,它也是所有动态代理类的父类

  • 如果在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy来创建动态代理类;
  • 如果需要为一个或多个接口动态地创建实例,也可以使用Proxy来创建动态代理实例。

创建动态代理类和动态代理实例的方法

Proxy提供了如下两个方法来创建动态代理类和动态代理实例。

方法 描述
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) 创建一个动态代理类所对应的 Class对象,该代理类将实现 interfaces所指定的多个接口。第一个 ClassLoader参数指定生成动态代理类的类加载器。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 直接创建一个动态代理对象,该代理对象的实现类实现了 interfaces指定的系列接口,执行代理对象的每个方法时都会被替换执行 Invocation Handler对象的 invoke方法
## 每个代理对象都有一个与之关联的InvocationHandler对象 ##
实际上,即使采用第一个方法生成动态代理类之后,如果程序需要通过该代理类来创建对象,依然需要传入一个InvocationHandler对象。也就是说,系统生成的每个代理对象都有一个与之关联的InvocationHandler对象

程序中可以采用先生成一个动态代理类,然后通过动态代理类来创建代理对象的方式生成一个动态代理对象。代码片段如下:

1
2
3
4
// 创建一个InvocationHandler对象
InvocationHandler handler = new MyInvokationHandler();
// 使用指定的InvocationHandler来生成一个动态代理对象
Person p = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[]{Person.class}, handler);

下面程序示范了使用ProxyInvocationHandler来生成动态代理对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.lang.reflect.*;

interface Person
{
void walk();
void sayHello(String name);
}
class MyInvokationHandler implements InvocationHandler
{
/*
执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
其中:
:代表动态代理对象
method:代表正在执行的方法
args:代表调用目标方法时传入的实参。
*/
public Object invoke(Object proxy, Method method, Object[] args)
{
System.out.println("----正在执行的方法:" + method);
if (args != null)
{
System.out.println("下面是执行该方法时传入的实参为:");
for (Object val : args)
{
System.out.println(val);
}
}
else
{
System.out.println("调用该方法没有实参!");
}
return null;
}
}
public class ProxyTest
{
public static void main(String[] args)
throws Exception
{
// 创建一个InvocationHandler对象
InvocationHandler handler = new MyInvokationHandler();
// 使用指定的InvocationHandler来生成一个动态代理对象
Person p = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[]{Person.class}, handler);
// 调用动态代理对象的walk()和sayHello()方法
p.walk();
p.sayHello("孙悟空");
}
}

上面程序首先提供了一个Person接口,该接口中包含了walk()sayHello()两个抽象方法,接着定义了一个简单的InvocationHandler实现类,定义该实现类时需要重写invoke()方法——调用代理对象的所有方法时都会被替换成调用该invoke()方法。该invoked方法中的三个参数解释如下:

  • proxy:代表动态代理对象。
  • method:代表正在执行的方法。
  • args:代表调用目标方法时传入的实参。

上面程序中第一行粗体字代码创建了一个InvocationHandler对象,第二行粗体字代码根据InvocationHandler对象创建了一个动态代理对象。运行上面程序,效果如下:

1
2
3
4
5
----正在执行的方法:public abstract void Person.walk()
调用该方法没有实参!
----正在执行的方法:public abstract void Person.sayHello(java.lang.String)
下面是执行该方法时传入的实参为:
孙悟空

不管程序是执行代理对象的walk()方法,还是执行代理对象的sayhello()方法,实际上都是执行InvocationHandler对象的invoked方法。

本文重点

执行代理对象的方法,实际上是执行InvocationHandler对象的invoke()方法。

原文链接: 18.5.1使用Proxy和InvocationHandler创建动态代理