JDK动态代理

  • 静态代理

用户接口:

1
2
3
4
5
6
7
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
19
20
21
22
23
24
25
26
27

/**
* 实现类
*/

public class UserImpl implements IUser{
public UserImpl(){

}

@Override
public void show(){
System.out.println("执行 => 展示");
}

@Override
public void create() {
System.out.println("执行 => 创建");
}

@Override
public void update() {
System.out.println("执行 => 更新");
}


}

Proxy:

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
import java.lang.reflect.Method;

/**
* 静态代理 实现IUser接口
* 起到通过代理 有日志记录的功能
*/
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("Proxy:调用 => show");
}

@Override
public void create() {
user.create();
System.out.println("Proxy:调用 => create");
}

@Override
public void update() {
user.update();
System.out.println("Proxy:调用 => update");
}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.lang.reflect.Proxy;

public class ProxyTest {
public static void main(String[] args){

//创建一个对象 用接口效果一样 继承关系
IUser user = new UserImpl();
// user.show(); 无代理 直接访问
//上代理 通过代理的好处 相当于租房找中介 有过程日志记录
//静态代理
IUser userProxy = new UserProxy(user);
userProxy.show();
userProxy.update();
userProxy.create();
}
}

效果:

image-20240818103836345

但是我们可以发现,上面的这种如果想对所有方法都进行代理,其实非常麻烦,每个函数方法都得写一遍

所以引出动态代理,可以自动找到对应的方法 不用重写了

  • 动态代理

ProxyTest:

1
2
3
4
5
6
//动态代理
//新建一个动态代理类 参数:要代理的接口、要做的事情、类加载器classloader
InvocationHandler userinvocationHandler = new UserInvocationHandler(user);
IUser userActiveProxy = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), userinvocationHandler);

userActiveProxy.create();

userinvocationHandler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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); // 接收到方法 利用invoke函数调用 参数时对象 和对应的方法值
return null;
}
}

image-20240818123723767

可以成功执行方法

但是没有 实现日志的效果 加一句话就ok了

image-20240818124209477

解释作用:

找到一个漏洞利用的点 B.f

入口是A(O) -> O.f2 意思:A接收参数O 然后调用O的f2方法

此时,如果O是动态代理类 O接收参数 进行调用f方法

O(X) invoke -> X.f 此时只需要把X传为B即可调用B.f

作用总结:

  1. readObject -> 反序列化自动执行
  2. invoke -> 有函数调用
  3. 拼接两条链