Java设计模式之代理模式

前言

代理模式:即通过代理对象访问目标对象,实现目标对象的方法。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,实现对目标功能的扩展。

这涉及到一个编程思想:不要随意去修改别人已经写好的代码或者方法(有坑)。如果需要修改,可以通过代理模式实现。

写法实现

代理模式通常有三种实现写法:静态代理、动态代理、Cglib代理

我们依次说下这三种代理模式:

我们现有 AnimalsDao接口和其实现AnimalsDaoImpl实现类,有两个方法,run和eat。

1
2
3
4
5
public interface AnimalsDao {  
//提供两个方法
void run();
void eat();
}
1
2
3
4
5
6
7
8
9
10
public class AnimalsDaoImpl implements AnimalsDao{  
@Override
public void run() {
System.out.println("run");
}
@Override
public void eat() {
System.out.println("eat");
}
}

现在我们想在run或者eat方法里之前做一些操作。

静态代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class StaticProxy implements AnimalsDao{  

@Override
public void run() {
System.out.println("StaticProxy--------->");
dao.run();
}

@Override
public void eat() {
System.out.println("StaticProxy--------->");
dao.eat();
}

private AnimalsDao dao;
public StaticProxy(AnimalsDao dao){
this.dao=dao;
}
}

说明:静态代理通过实现目标对象接口,然后调用相同方法来实现代理。这种方式的缺点显而易见,当目标对象接口方法变动时,直接影响到代理类,需要对代理类进行修改,十分不方便。而且如果目标对象接口方法较多时,代理类也十分臃肿,不便维护。

动态代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class DynamicProxy {  
//要代理的对象
private Object obj;
public DynamicProxy(Object obj){
this.obj=obj;
}

public Object getObjProxyIntance(){
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行目标对象方法
System.out.println("DynamicProxy--------->");
return method.invoke(obj,args);
}
});
}
}

说明:动态代理模式主要借助JDK代理对象API java.lang.reflect.Proxy来实现的,所以也称作JDK代理。我们看一下JDK这个类,其中重要的一个方法如下:

upload successful

这个方法的三个参数:

ClassLoader loader 目标对象类加载器

Class<?>[] interfaces 目标对象接口类型

InvocationHandler h 事物处理,在这里面可以实现自己想要的逻辑

根据以上,可以看出动态代理实现要求目标对象必须有实现接口。代理类不必实现接口。

Cglib代理

要实现Cglib代理,必须引入cglib.jar 包,由于Spring-core包中已经包含了cglib功能,且大部分Java项目均引入了spring 相关jar包,这边使用spring的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
public class CglibProxy implements MethodInterceptor {  

//目标对象
private Object obj;
public CglibProxy(Object obj){
this.obj=obj;
}

//给目标对象创建一个代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(obj.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CglibProxy--------->");
return method.invoke(obj,objects);
}
}

说明:可以看出,Cglib代理模式实现不需要目标对象一定实现接口,故目标对象如果没有实现接口,可以使用cglib代理模式。其实Spring的代理模式也是这么实现的。

应用实例

Spring的代理模式:如果容器目标对象有接口,使用JDK动态代理,如果没有接口,使用cglib动态代理。

upload successful

参考资料

  1. https://www.cnblogs.com/cenyu/p/6289209.html

  2. Spring 4.0 源代码

GitHub代码地址

https://github.com/JavaZWT/designPatterns




-------------文章结束啦 ~\(≧▽≦)/~ 感谢您的阅读-------------

您的支持就是我创作的动力!

欢迎关注我的其它发布渠道