动态代理
# 动态代理
# 什么是动态代理
Spring 的动态代理是指在程序运行时动态地生成代理对象,代理对象可以在不改变原有代码的情况下增强原有代码的功能。Spring 的动态代理主要有两种方式:基于 JDK 的动态代理和基于 CGLIB 的动态代理。
# 基于 JDK 的动态代理
基于 JDK 的动态代理是指使用 Java 提供的 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来生成代理对象。JDK 动态代理只能代理实现了接口的类。
使用 JDK 动态代理时,需要定义一个 InvocationHandler 接口的实现类,该类实现 InvocationHandler 接口的 invoke 方法,代理对象的所有方法都将被重写为调用该方法。在 invoke 方法中,可以通过反射调用目标对象的方法,并在方法调用前后进行一些增强操作。
使用 JDK 动态代理的步骤如下:
定义一个 InvocationHandler 接口的实现类,实现 invoke 方法。
使用 Proxy.newProxyInstance 方法生成代理对象,该方法需要传入目标对象、目标对象的接口类型和 InvocationHandler 对象。
使用代理对象调用目标方法。
# 基于 CGLIB 的动态代理
基于 CGLIB 的动态代理是指使用 CGLIB 库来生成代理对象。CGLIB 是一个强大的高性能代码生成库,可以在运行时扩展 Java 类和实现接口。
使用 CGLIB 动态代理时,需要定义一个 MethodInterceptor 接口的实现类,该类实现 MethodInterceptor 接口的 intercept 方法,代理对象的所有方法都将被重写为调用该方法。在 intercept 方法中,可以通过反射调用目标对象的方法,并在方法调用前后进行一些增强操作。
使用 CGLIB 动态代理的步骤如下:
- 定义一个 MethodInterceptor 接口的实现类,实现 intercept 方法。
- 使用 Enhancer.create 方法生成代理对象,该方法需要传入目标对象的类类型和 MethodInterceptor 对象。
- 使用代理对象调用目标方法。
总体来说,Spring 的动态代理可以很好地解耦业务逻辑和增强逻辑,使得代码更加灵活可扩展。
# 基于接口的动态代理
- 涉及的类 proxy:提供者:jdk 官方
如何创建代理对象:Proxy 中的 newInstance ()
创建代理对象的要求:被代理类至少实现一个接口,如果没有则不能使用。
newProxyInstance 的参数
ClassLoader loader:写被代理类的类加载器,固定写法。
<bean id="exampleBean" class="org.example.hello.spring.pojo.ExampleBean"> <property name="arrayProperty"> <array> <value>Value 1</value> <value>Value 2</value> <value>Value 3</value> </array> </property> <property name="listProperty"> <list> <value>Value 1</value> <value>Value 2</value> <value>Value 3</value> </list> </property> <property name="setProperty"> <set> <value>Value 1</value> <value>Value 2</value> <value>Value 3</value> </set> </property> <property name="mapProperty"> <map> <entry key="Key 1" value="Value 1"/> <entry key="Key 2" value="Value 2"/> <entry key="Key 3" value="Value 3"/> </map> </property> </bean>
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
30InvocationHandler h:写如何代理,通常情况下就是匿名内部类,但不是必须的。
以买电脑业务逻辑来说明
/**
* 一个生产者
*/
public interface IProducer {
/**
* 销售
*
* @param money
*/
public void sellProduct(Float money);
/**
* 售后
*
* @param money
*/
public void afterSell(Float money);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
需要一个实现类来实现这两个方法
/**
* 一个生产者
*/
public class Producer implements IProducer {
/**
* 销售
*
* @param money
*/
public void sellProduct(Float money) {
System.out.println("销售了产品,并且拿到了" + money + "钱");
}
/**
* 售后
*
* @param money
*/
public void afterSell(Float money) {
System.out.println("提供了售后服务,并且拿到了" + money + "钱");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
写一个测试类,当生产商卖出一台电脑,会有百分之 20 的收入进入到经销商的手中,所以我们定一个增强的方法,这个代理方式是基于接口来实现的。只要是接口中的方法执行都会经过这个代理方法中
/**
* 模拟一个消费者
*/
public class Client {
@Test
public void buy() {
final Producer producer = new Producer();
//producer.sellProduct(5000f);
/*
动态代理
优点,字节码随用随创建,随用随加载.
作用:不修改源码的基础上对方法增强
分类:基于接口的动态代理
涉及的类proxy,
提供者:jdk官方
如何创建代理对象
Proxy中的newInstance(),
创建代理对象的要求
被代理类至少实现一个接口,如果没有则不能使用.
newProxyInstance的参数
ClassLoader loader,
写被代理类的类加载器,固定写法
Class<?>[] interfaces,
写被代理类的getInterfaces(),固定写法
InvocationHandler h
写如何代理,通常情况下就是匿名内部类,但不是必须的
基于子类的动态代理
*/
IProducer iproducer = (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 {
Object object = null;
//提供增强的代码
//获取方法执行的参数
Float money = (Float) args[0];
//判断当前方法是不是销售
if ("sellProduct".equals(method.getName())) {
object = method.invoke(producer, money * 0.8f);
}
return object;
}
});
iproducer.sellProduct(8000f);
}
}
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
54
55
# 基于子类的动态代理
这个代理方法必须有第三方的 jar 包才可以实现 (cglib)
/**
* 模拟一个消费者
*/
public class Client {
@Test
public void buy() {
final Producer producer = new Producer();
//producer.sellProduct(5000f);
/*
动态代理
优点,字节码随用随创建,随用随加载.
作用:不修改源码的基础上对方法增强
分类:基于子类的动态代理
涉及的类enhancer,
提供者:第三方jar
如何创建代理对象
enhancer中的create(),
创建代理对象的要求
被代理类不能是final类
create的参数
Class type,
写被代理类的类加载器,固定写法
Callback callback
用于提供增强的,只不过一般写的都是实现类
*/
Producer proder = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {
/**
* 被代理对象的任何方法都会经过该方法
* @param o 代理对象的引用
* @param method 当前执行的方法
* @param objects 方法所需要的参数
* 以上三个和基于接口代理的invoke()中的三个参数是完全一致的
* @param methodProxy 当前执行方法的代理对象
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object object = null;
//提供增强的代码
//获取方法执行的参数
Float money = (Float) objects[0];
//判断当前方法是不是销售
if ("sellProduct".equals(method.getName())) {
object = method.invoke(producer, money * 0.8f);
}
return object;
}
});
proder.sellProduct(20000f);
}
}
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