JDK动态代理
静态代理
理解为租客,中介和房东之间的关系,中介就是代理
先定义一个接口
1
2
3
4
5
6
7
8
|
package Proxy;
public interface IUser {
void show();
// void create();
// void update();
}
|
然后写一个类来实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package Proxy;
public class UserImpl implements IUser {
public UserImpl() {
}
@Override
public void show() {
System.out.println("show");
}
// @Override
// public void create() {
// System.out.println("create");
// }
// @Override
// public void update() {
// System.out.println("update");
// }
}
|
写一个类作为代理调用上面的实现类
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
|
package Proxy;
public class UserProxy implements IUser {
IUser user;
public UserProxy() {
}
public UserProxy(IUser user) {
this.user = user;
}
@Override
public void show() {
user.show();
System.out.println("show");
}
// @Override
// public void create() {
// user.create();
// System.out.println("create");
// }
// @Override
// public void update() {
// user.update();
// System.out.println("update");
// }
}
|
然后调用这个代理类
1
2
3
4
5
6
7
8
9
10
|
package Proxy;
public class ProxyTest {
public static void main(String[] args) {
IUser user = new UserImpl();
// user.show();
IUser userProxy = new UserProxy(user);
userProxy.show();
}
}
|
缺点就是如果我们接口需要多写一个功能,就要写大量重复的代码,而且想到通过反射来实现,我们获取不到对应的方法,也实现不了
动态代理
首先就是要用到Proxy
这个类,然后里面的newProxyInstance
方法
1
2
3
4
5
6
7
8
9
10
11
12
|
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
Objects.requireNonNull(h);
/*
* Look up or generate the designated proxy class and its constructor.
*/
Constructor<?> cons = getProxyConstructor(loader, interfaces);
return newProxyInstance(cons, h);
}
|
可以看到它需要一个类加载器,若干个接口数组,第三个就是我们想要用这个代理做的事情
前两个参数都可以这样获取
1
|
Proxy.newProxyInstance(user.getClass().getClassLoader(),user.getClass().getInterfaces(),h);
|
然后下面我们写第三个参数,新建一个类继承InvocationHandler
接口
1
2
|
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
|
所以我们这个类就是要重写invoke
方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class UserInvocationHandler implements InvocationHandler {
IUser user;
public UserInvocationHandler() {
}
public UserInvocationHandler(IUser user) {
this.user = user;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(user,args);
return null;
}
}
|
接着就可以填上前面缺的第三个参数了
1
2
|
UserInvocationHandler handler = new UserInvocationHandler(user);
IUser userProxy= (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(),user.getClass().getInterfaces(),handler);
|
想要实现什么重复的功能,只需要再前面那个类中写就行了,因为它会帮我们获取方法
反序列化中动态代理的应用
假设有一个最终能利用的类B
B.f能命令执行,然后我们现在有一个入口类A,
我们希望有一个参数O,使得A.[O] -> O.f
来实现,但是实战往往不能实现
如果这个参数O是一个动态代理类,我们可以用重写invoke
方法,调用f方法,来实现利用
这跟readObject
方法一样,invoke
方法在动态代理会自动执行