动态代理

​ 除了装饰者模式,动态代理也可用于进行方法增强,并且不用编写相关类,在不修改源码的情况下起到增强方法的作用。

1.基于接口的动态代理

​ 此方法使用 jdk 自带的 api 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
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
public class Producer implements IProducer{
@Override
public void sale(float money) {
System.out.println("销售产品,并拿到钱:"+money);
}

@Override
public void afterSale(float money) {
System.out.println("提供售后服务,并拿到钱:"+money);
}
}

public class Client {

public static void main(String[] args) {
Producer producer = new Producer();
/**
* 获取代理对象:
* 要求:
* 被代理类最少实现一个接口
* 创建的方式:
* Proxy.newProxyInstance(三个参数)
* 参数含义:
* ClassLoader:和被代理对象使用相同的类加载器。
* Interfaces:和被代理对象具有相同的行为。实现相同的接口
* InvocationHandler:如何代理,一般由匿名内部类实现
*
*/
IProducer proxyInstance = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 执行被代理对象的任何方法,都会经过该方法
* 此方法有拦截的功能

* @param proxy 代理对象的引用,不一定每次都能用到
* @param method 当前执行的方法对象
* @param args 执行方法所需的参数
* @return 当前执行方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
float money = (float) args[0];
if (method.getName().equals("sale")) {
money *= 0.8f;
}
return method.invoke(producer, money);
}
});
proxyInstance.sale(10000f);

}
}

2.基于子类的动态代理

​ 如果被代理对象没有实现接口,就要使用基于子类的动态代理,要求被代理对象不能是最终类,使用Enhancer类的create方法,利用了cglib,使用maven的项目需导入坐标

1
2
3
4
5
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>

具体例子如下:

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
public class Producer{

public void sale(float money) {
System.out.println("销售产品,并拿到钱:"+money);
}


public void afterSale(float money) {
System.out.println("提供售后服务,并拿到钱:"+money);
}
}

public class Client {
public static void main(String[] args) {
final Producer producer = new Producer();
/**
* 基于子类的动态代理
* 要求:
* 被代理对象不能是最终类
* 用到的类:
* Enhancer
* 用到的方法:
* create(Class,Callback)
* 方法的参数:
* Class:被代理对象的字节码
* Callback:如何代理,一般用其子接口MethodInterceptor匿名类实现
*/
Producer proxyProducer = (Producer) Enhancer.create(producer.getClass(),
new MethodInterceptor() {
/**
*
* @param proxy 代理对象的引用。不一定每次都用得到
* @param method 当前执行的方法对象
* @param args 执行方法所需的参数
* @param methodProxy 当前执行方法的代理对象
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
float money = (float) args[0];
if (method.getName().equals("sale")) {
money *= 0.8f;
}
return method.invoke(producer, money);
}
});
proxyProducer.sale(10000f);
}
}

使用过动态代理之后可以对Producer的sale方法进行增强,将收到钱数额变成原来的0.8倍。

Comments