Java动态代理

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。

静态代理

创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。

简而言之就是接口和实现接口的类,接口定义了某种方法,实现接口的类需要去重写方法。

但是静态代理只能代理一个类,如果有多个类需要代理就不能用静态代理实现了,这时候要用动态代理来实现。动态代理可以很方便的对代理类的函数进行统一的处理(invoke),而不是修改每个代理类的函数,更灵活和扩展。

与静态代理相比,动态代理是在运行时动态生成一个代理类(Java反射机制可以在运行时生成类),该类可以对目标对象的方法进行功能增强。之前学习Java反射机制时提到了反射机制可以生成动态代理,

动态代理

网上看Java动态代理貌似有两种,基于JDK的动态代理和基于CGILB的动态代理,我们在这里只学习下JDK的动态代理,如果后面要用到另一种,再去学习。JDK动态代理有两个重要的类或接口, InvocationHandler(Interface)和Proxy(Class),实现我们动态代理必须用到它们。先来看下这两个类。

InvocationHandler(Interface)

先来看下,里面的源码是我加的注释

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package java.lang.reflect;

/**
* {@code InvocationHandler} is the interface implemented by
* the <i>invocation handler</i> of a proxy instance.
* InvocationHandler是一个接口,被代理实例实现
*
* <p>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 {@code invoke}
* method of its invocation handler.
*每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,
*当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用
*
* @author Peter Jones
* @see Proxy
* @since 1.3
*/
public interface InvocationHandler {

/**
* 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.
*
* @param proxy the proxy instance that the method was invoked on
*
* @param method the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance. The declaring
* class of the {@code Method} object will be the interface that
* the method was declared in, which may be a superinterface of the
* proxy interface that the proxy class inherits the method through.
*
* @param args an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* or {@code null} if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* {@code java.lang.Integer} or {@code java.lang.Boolean}.
*
* @return the value to return from the method invocation on the
* proxy instance. If the declared return type of the interface
* method is a primitive type, then the value returned by
* this method must be an instance of the corresponding primitive
* wrapper class; otherwise, it must be a type assignable to the
* declared return type. If the value returned by this method is
* {@code null} and the interface method's return type is
* primitive, then a {@code NullPointerException} will be
* thrown by the method invocation on the proxy instance. If the
* value returned by this method is otherwise not compatible with
* the interface method's declared return type as described above,
* a {@code ClassCastException} will be thrown by the method
* invocation on the proxy instance.
*........
* .......
* @see UndeclaredThrowableException
*/
/**
*唯一要去实现的方法:invoke
*三个参数:Object proxy, Method method, Object[] args
*proxy:代理的对象
*method:调用真实对象的某个方法的Method对象
*args:调用真实对象某个方法时接受的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}

Proxy(Class)

Proxy这个类的作用就是用来动态创建一个代理对象的类。如下图,可以看到Proxy实现了Serializable接口,他有很多成员变量和方法,其中newProxyInstance是需要经常用到的,所以就分析它好了。

image-20200606110709033
1
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

实例:

newProxyInstance需要三个参数(目标接口,实现目标接口的子类,扩展处理器-处理目标接口的handler),首先把三个参数准备好分别是ImpTest.class.getClassLoader()、ImpTest.class.getInterfaces()和handler,测试的时候遇到一个错误,就是代理类必须要实现接口,我们代理的时候是代理接口的方法,这里是Test.test()和Test.test1(),所以当我们调用proxy.test()和proxy.test1()都会去调用handler.invoker()方法。

所以就是说在这个实例中,我们是用handler.invoker()去代理Test接口的所有方法。

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
49
50
51
52
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {
public static void main(String[] args) {
Handler handler = new Handler(new ImpTest());
// proxy必须以代理类的接口作为类型,否则会报错
Test proxy = (Test)Proxy.newProxyInstance(ImpTest.class.getClassLoader(), ImpTest.class.getInterfaces(), handler);
System.out.println(proxy.test());
System.out.println(proxy.test1(" 123"));
}
}

interface Test{
abstract String test();
public String test1(String a);
}

class ImpTest implements Test {

@Override
public String test() {
return "这里是被代理类的方法:test";
}
@Override
public String test1(String a){
return "这里是被代理类的方法:test1" + a;
}
}

class Handler implements InvocationHandler{
private Object object;

Handler(Object object){
this.object = object;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("test")){
System.out.println("在这里调用test方法");
System.out.println(method.invoke(object, args));
return "test";
}else if(method.getName().equals("test1")){
System.out.println("在这里调用test1方法");
System.out.println(method.invoke(object, args));
return "test1";
}
return null;
}
}

运行结果:

image-20200728144025777

动态代理具体步骤:

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

参考链接:

https://www.cnblogs.com/gonjan-blog/p/6685611.html

https://blog.csdn.net/weixin_40558287/article/details/103058052

https://blog.csdn.net/qq_32532321/article/details/81874990

https://www.jianshu.com/p/9bcac608c714

https://www.cnblogs.com/xiaoluo501395377/p/3383130.html

https://www.anquanke.com/post/id/202730