Java中的代理设计模式
本文最后更新于:1 年前
代理设计模式的优点:将通用性的工作都交给代理对象完成,被代理对象只需专注自己的核心业务。
- 被代理类中只用关注核心业务的实现,将通用的管理型逻辑(事务管理、日志管理)和业务逻辑分离;
- 将通用的代码放在代理类中实现,提高了代码的复用性;
- 通过在代理类添加业务逻辑,即可实现对原有业务逻辑的扩展(增强)。
生活中的代理
代理设计模式的优点:将通用性的工作都交给代理对象完成,被代理对象只需专注自己的核心业务。
静态代理
静态代理中,代理类只能够为特定的类生产代理对象,不能代理任意类。
使用代理的好处:
- 被代理类中只用关注核心业务的实现,将通用的管理型逻辑(事务管理、日志管理)和业务逻辑分离;
- 将通用的代码放在代理类中实现,提高了代码的复用性;
- 通过在代理类添加业务逻辑,即可实现对原有业务逻辑的扩展(增强)。
动态代理
动态代理,几乎可以为所有的类产生代理对象。
动态代理的实现方式有2种:
- JDK 代理 : 基于接口的动态代理技术。
- cglib 代理:基于父类的动态代理技术。
JDK 代理
JDK动态代理是通过被代理对象实现的接口产生其代理对象的。
写法一
JDK动态代理类实现
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/***
* JDK动态代理:是通过被代理对象实现的接口产生其代理对象的
* 1.创建一个类,实现InvocationHandler接口,重写invoke方法
* 2.在类种定义一个Object类型的变量,并提供这个变量的有参构造器,用于将被代理对象传递进来
* 3.定义getProxy方法,用于创建并返回代理对象
*/
public class JDKDynamicProxy implements InvocationHandler {
//被代理对象
private Object obj;
public JDKDynamicProxy(Object obj) {
this.obj = obj;
}
//产生代理对象,返回代理对象
public Object getProxy(){
//1.获取被代理对象的类加载器
ClassLoader classLoader = obj.getClass().getClassLoader();
//2.获取被代理对象的类实现的接口
Class<?>[] interfaces = obj.getClass().getInterfaces();
//3.产生代理对象(通过被代理对象的类加载器及实现的接口)
//第一个参数:被代理对象的类加载器
//第二个参数:被代理对象实现的接口
//第三个参数:使用产生代理对象调用方法时,用于拦截方法执行的处理器
Object proxy = Proxy.newProxyInstance(classLoader, interfaces,this);
return proxy;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
begin();
Object returnValue = method.invoke(obj,args); //执行method方法(insert)
commit();
return returnValue;
}
public void begin(){
System.out.println("----------开启事务");
}
public void commit(){
System.out.println("----------提交事务");
}
}测试类
1
2
3
4
5
6
7
8
9
10
11
12
13//创建被代理对象
BookDAOImpl bookDAO = new BookDAOImpl();
StudentDAOImpl studentDAO = new StudentDAOImpl();
//创建动态代理类对象,并将被代理对象传递到代理类中赋值给obj
JDKDynamicProxy jdkDynamicProxy = new JDKDynamicProxy(studentDAO);
//proxy就是产生的代理对象:产生的代理对象可以强转成被代理对象实现的接口类型
GenaralDAO proxy = (GenaralDAO)jdkDynamicProxy.getProxy();
//使用代理对象调用方法,并不会执行调用的方法,而是进入到创建代理对象时指定的InvocationHandler类种的invoke方法
//调用的方法作为一个Method参数,传递给了invoke方法
proxy.insert(student);
写法二
目标类接口
1
2
3public interface TargetInterface {
public void save();
}目标类
1
2
3
4
5
6public class Target implements TargetInterface {
@Override
public void save() {
System.out.println("save running……");
}
}未使用动态代理增强
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
30public class ProxyTest {
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//返回值,就是动态生成的代理对象
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
//目标对象类加载器
target.getClass().getClassLoader(),
//目标对象相同的接口字节码对象数组
target.getClass().getInterfaces(),
new InvocationHandler() {
//调用代理对象的任何方法,实质执行的都是invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行目标方法
method.invoke(target, args);
return null;
}
}
);
//调用代理对象的方法
proxy.save();
}
}被用来代理的类
1
2
3
4
5
6
7
8
9
10public class Advice {
public void before(){
System.out.println("前置增强……");
}
public void after(){
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
33public class ProxyTest {
public static void main(String[] args) {
//目标对象
final Target target = new Target();
//增强对象
Advice advice = new Advice();
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强
advice.before();
method.invoke(target, args);
//后置增强
advice.after();
return null;
}
}
);
//调用代理对象的方法
proxy.save();
}
}
cglib 代理
由于JDK动态代理是通过被代理类实现的接口来创建代理对象的,因此JDK动态代理只能代理实现了接口的类的对象。如果一个类没有实现任何接口,该如何产生代理对象呢?
CGLib动态代理,是通过创建被代理类的子类来创建代理对象的,因此即使没有实现任何接口的类也可以通过CGLib产生代理对象。
CGLib动态代理不能为final类创建代理对象。
案例一
添加CGLib的依赖
1
2
3
4
5
6<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>CGLib动态代理实现
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/**
* 1.添加cglib依赖
* 2.创建一个类,实现MethodInterceptor接口,同时实现接口中的intercept方法
* 3.在类中定义一个Object类型的变量,并提供这个变量的有参构造器,用于传递被代理对象
* 4.定义getProxy方法创建并返回代理对象(代理对象是通过创建被代理类的子类来创建的)
*/
public class CGLibDynamicProxy implements MethodInterceptor {
private Object obj;
public CGLibDynamicProxy(Object obj) {
this.obj = obj;
}
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxy = enhancer.create();
return proxy;
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
begin();
Object returnValue = method.invoke(obj,objects); //通过反射调用被代理类的方法
commit();
return returnValue;
}
public void begin(){
System.out.println("----------开启事务");
}
public void commit(){
System.out.println("----------提交事务");
}
}测试类
1
2
3
4
5
6
7
8
9
10
11//创建被代理对象
BookDAOImpl bookDAO = new BookDAOImpl();
StudentDAOImpl studentDAO = new StudentDAOImpl();
//通过cglib动态代理类创建代理对象
CGLibDynamicProxy cgLibDynamicProxy = new CGLibDynamicProxy(bookDAO);
//代理对象实际上是被代理对象子类,因此代理对象可直接强转为被代理类类型
BookDAOImpl proxy = (BookDAOImpl) cgLibDynamicProxy.getProxy();
//使用对象调用方法,实际上并没有执行这个方法,而是执行了代理类中的intercept方法,将当前调用的方法以及方法中的参数传递到intercept方法
proxy.update();
案例二
导入 pom 坐标
spring-context 已经集成了 cglib 相关依赖,只需导入 spring-context 即可。
1
2
3
4
5
6
7
8
9
10
11
12
13<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>目标类
1
2
3
4
5
6public class Target implements TargetInterface {
@Override
public void save() {
System.out.println("save running……");
}
}动态代理代码
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
36public class ProxyTest {
public static void main(String[] args) {
//目标对象
final cc.gaojie.proxy.jdk.Target target = new Target();
//增强对象
Advice advice = new Advice();
//返回值,就是动态生成的代理对象,基于cglib
//1. 创建增强器
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(Target.class);
//设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
//执行前置
System.out.println("前置代码增强....");
//执行目标
Object invoke = method.invoke(target, objects);
//执行后置
System.out.println("后置代码增强....");
return invoke;
}
});
//创建代理对象
Target proxy = (Target) enhancer.create();
//测试,当调用接口的任何方法时,代理对象的代码都无序修改
proxy.save();
}
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!