Java / 代理模式

代理模式的一个典型应用:AOP(面向切面编程)

代理

a类本来需要调用c类(目标类)的方法完成某个功能, 但是c不让a调用。

a —>不能直接调用 c的方法。
在a 和 c 直接创建一个 b 代理,c让b访问。 c,b实现相同的功能(接口)。
a —>访问b—>访问c

作用:

  • 功能增强: 在原有的功能上,增加了额外的功能。 新增加的功能,叫做功能增强
  • 控制访问: 代理类不让你访问目标,例如商家不让用户访问厂家。

静态代理

代理类需要手工实现。即自己创建一个java类,表示代理类。所要代理的目标类是确定的。

  • 缺点:当目标类和代理类很多时候,
    • 当目标类增加, 代理类可能也需要成倍的增加。 代理类数量过多。
    • 当接口中功能增加或修改,会影响众多的实现类,厂家类,代理类都需要修改。影响较大。

动态代理

在程序执行过程中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类。
即使目标类很多,代理类数量可以很少;当修改了接口中的方法时,不影响代理类。
动态代理是一种创建java对象的能力,不用创建代理类,就能创建代理类对象。
两种实现方式:jdk动态代理;cglib动态代理

jdk动态代理

  • 使用java反射包中的类和接口实现动态代理的功能。
  • 反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Method, Proxy.
  • 要求目标类实现接口
1
2
3
4
5
6
7
8
// 不使用反射调用方法
HelloService service = new HelloServiceImpl(); //创建类对象service
service.sayHello("张三"); // 通过对象调用sayHello()方法

// 使用反射调用方法
Method method = HelloService.class.getMethod("sayHello", String.class); // 获取method对象(sayHello()方法)
HelloService service2 = new HelloServiceImpl2();
Object ret = method.invoke(service2, "李四"); // invoke()方法调用对象service2的方法
  • InvocationHandler接口,只有一个方法invoke(),代理对象要完成的功能。(目标方法/功能增强)
  • Method类:表示目标类中的方法。通过Method可以执行某个目标类的方法,method.invoke(目标对象,方法的参数)
  • Proxy类:创建代理对象。之前创建对象是 new ,现在使用Proxy类的静态方法 newProxyInstance() 。
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
//实现InvocationHandler接口,完成代理类要做的功能(1.调用目标方法,2.功能增强)
public class MySellHandler implements InvocationHandler {
private Object target = null; // 为目标类创建对象(活动的,不是固定的,需要传入进来)
public MySellHandler(Object target) {
this.target = target;
}

// 实现invoke方法,完成代理类要做的功能
// Object proxy: jdk创建的代理对象,无需赋值。
// Method method: 目标类中的方法,jdk提供
// Object[] args:目标类中方法的参数, jdk提供。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = null;
res = method.invoke(target,args); // 反射,执行目标对象target的method方法
//功能增强,加价
if( res != null ){
Float price = (Float)res;
price = price + 25;
res = price;
}
System.out.println(res);
return res;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
//创建代理对象,使用Proxy
//1. 创建目标对象
UsbSell factory = new UsbKingFactory();
//2.创建InvocationHandler对象
InvocationHandler handler = new MySellHandler(factory);
//3.创建代理对象
UsbSell proxy = (UsbSell) Proxy.newProxyInstance(
factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(),
handler
);
//4.通过代理执行方法
float price = proxy.sell(1); // 代理对象proxy调用目标类factory中的sell方法

cglib动态代理

  • cglib是第三方的工具库, 创建代理对象。
  • 原理是继承, cglib通过继承目标类,创建它的子类,在子类中重写父类中同名的方法, 实现功能的修改。要求目标类不能是final的, 方法也不能是final的。
  • cglib的要求目标类比较宽松, 只要能继承即可。