Java代理

Chiexf Lv4

0x00 静态代理

概述

  • 在程序运行前已经存在代理类

示例

对象

1
2
3
public class Student {
String name;
}

接口类

1
2
3
public interface StudentService {
public void findName();
}

实现类、被代理类

1
2
3
4
5
6
public class StudentServiceImpl implements StudentService{
@Override
public void findName() {
System.out.println("正在查询");
}
}

代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class StudentServiceImplProxy implements StudentService{
//目标类对象
private StudentServiceImpl studentService;
//通过构造器获取目标类
public StudentServiceImplProxy(StudentServiceImpl studentService)
{
this.studentService = studentService;
}

//新增方法
public void deleteName(){
System.out.println("删除学生");
}

@Override
public void findName() {
studentService.findName();
deleteName();
}
}

测试类

1
2
3
4
5
6
7
8
9
10
public class TestProxy {
@Test
public void testProxy(){
//被代理对象
StudentServiceImpl studentService = new StudentServiceImpl();
// studentService.findName();
StudentServiceImplProxy studentServiceImplProxy = new StudentServiceImplProxy(studentService);
studentServiceImplProxy.findName();
}
}
  • 输出
1
2
正在查询
删除学生

缺点

  • 不利于代码拓展,比如接口中新添加一个抽象方法时,所有实现类都需要重新实现,否则报错。
  • 代理对象需要创建很多。

0x01 动态代理

概述

  • 运行期间才确定的代理

示例

接口类

1
2
3
public interface RentService {
public void rent();
}

实现类

1
2
3
4
5
public class RentServiceImpl implements RentService {
public void rent() {
System.out.println("房屋出租");
}
}

代理类

Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

  • Proxy.newProxyInstance()

是 JDK 提供的一个方法,用于创建动态代理对象,拦截和处理方法调用,并可以在调用前后添加自定义的逻辑。返回一个实现了指定接口的代理对象。该代理对象会将方法调用转发给指定的 InvocationHandler 对象,并由 InvocationHandler 来处理方法调用的逻辑。这样,我们就可以在方法调用前后进行一些自定义的处理或附加操作。

  • ClassLoader loader

用于定义代理类的类加载器。(用代理类的加载器就行)

  • Class<?>[] interfaces

代理类需要实现的接口列表。

  • InvocationHandler h

一个实现了 InvocationHandler 接口的对象,用于拦截方法调用并定义代理逻辑。

invoke(Object proxy, Method method, Object[] args)

  • invoke()

我们可以在 invoke() 方法内部编写处理逻辑,比如在调用目标方法之前做一些额外的处理,或者根据方法名或参数类型来进行特定的操作。然后,可以通过反射机制调用真实对象的方法,完成方法调用的转发。最后,还可以通过返回值来处理方法调用的结果。需要注意的是,invoke() 方法的返回值是 Object 类型,表示被调用方法的返回值。如果被调用的方法是一个 void 方法,则 invoke() 方法的返回值应为 null

  • Object proxy

表示动态代理生成的代理对象。在 invoke() 方法中,如果需要调用代理对象的方法,可以使用这个参数

  • Method method

表示被调用的方法对象。通过这个参数,可以获取方法名、参数列表等方法相关的信息。

  • Object[] args

表示方法的参数列表。它是一个数组,包含了方法调用时传入的实际参数。

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
public class RentServiceImplProxy {
private RentService rentService;

public RentServiceImplProxy(RentService rentService) {
this.rentService = rentService;
}

public RentService creatProxy() {
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object invoke = method.invoke(rentService, args);
fare();
return invoke;
}
};

RentService proxyInstance = (RentService)Proxy.newProxyInstance(RentServiceImplProxy.class.getClassLoader(),
new Class[]{RentService.class},
invocationHandler);
return proxyInstance;
}

//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
  • 另一种写法(大差不差)
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
public class RentServiceImplProxy implements InvocationHandler {
private RentService rentService;

public RentServiceImplProxy(RentService rentService) {
this.rentService = rentService;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
Object result = method.invoke(rentService, args);
fare();
return result;
}

//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}

//动态获取代理
public Object creatProxy() {
Object p = Proxy.newProxyInstance(RentServiceImplProxy.class.getClassLoader(),
new Class[]{RentService.class},
this
);
return p;
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
public class TestProxy {
@Test
public void testProxy(){
RentServiceImpl rentService = new RentServiceImpl();

//代理实例的调用处理程序
RentServiceImplProxy rentServiceImplProxy = new RentServiceImplProxy(rentService);
//动态生成对应的代理类!
RentService rentService1 = (RentService) rentServiceImplProxy.creatProxy();
rentService1.rent();
}
}
  • 输出
1
2
3
带房客看房
房屋出租
收中介费