代理模式

前言

代理模式是一种常见的设计模式,它使用代理对象完成用户请求,屏蔽了用户对真实对象的访问。

在软件设计中,使用代理模式的意图也很多。比如因为安全原因,屏蔽客户端直接访问真实对象。或者在远程调用中,使用代理类来屏蔽远程方法调用的技术细节。或为了提升系统性能,将真实对象封装,达到延迟加载的目的。比如hibernate就使用了cglib来实现延迟加载。
这里使用代理模式实现延迟加载,提升系统性能和速度。

不使用代理模式的直接调用

这里定义一个IUserService接口类,提供一个request方法;UserService实现IUserService接口。Main为测试类。

1
2
3
4
5
6
/**
* Created by j.tommy on 2017/9/10.
*/
public interface IUserService {
String request();
}

1
2
3
4
5
6
7
8
9
/**
* Created by j.tommy on 2017/9/10.
*/
public class UserService implements IUserService {
@Override
public String request() {
return "hello";
}
}
1
2
3
4
5
6
7
8
9
10
/**
* Created by j.tommy on 2017/9/10.
*/
public class Main {
public static void main(String[] args) {
IUserService ius = new UserService();
String result = ius.request();
System.out.println("result:" + result);
}
}

静态代理

下面定义一个UserServiceProxy来代理UserService,对外提供服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* Created by j.tommy on 2017/9/10.
*/
public class UserServiceProxy implements IUserService {
private UserService us = null;
@Override
public String request() {
// 延迟加载us的实例,在实际使用时初始化
if (null == us) {
us = new UserService();
System.out.println("Created UserService.");
}
return us.request();
}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Created by j.tommy on 2017/9/10.
*/
public class Main {
public static void main(String[] args) {
// 通过代理类调用
IUserService ius = new UserServiceProxy();
System.out.println("Created proxy.");
String result = ius.request();
System.out.println("result:" + result);
}
}

输出:

可以看到,在实际调用request()方法时才初始化UserService.
静态代理很大的一个问题:所有的代理类必须实现接口,现在是一个UserService,如果还有其他的XXService,每个XXServiceProxy都需要实现XXService接口,这是很麻烦的。

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
/**
* jdk动态代理。
* Created by j.tommy on 2017/9/10.
*/
public class JdkDynamicProxy implements InvocationHandler {
// 真实对象
private Object target;
public JdkDynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用真实对象的方法
Object result = method.invoke(target,args);
return result;
}
/**
* 获取目标对象的代理对象
* @return
*/
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Created by j.tommy on 2017/9/10.
*/
public class Main {
public static void main(String[] args) {
// JDK动态代理
// 真实对象
IUserService ius = new UserService();
// 代理对象
IUserService us = (IUserService) new JdkDynamicProxy(ius).getProxy();
String result = us.request();
System.out.println("result:" + result);
}
}

如上代码,可以代理任何接口。但它也有个问题,要代理的类必须实现接口。。如果不想实现接口,还要能够代理,可以使用cglib.

cglib动态代理

cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Created by j.tommy on 2017/9/10.
*/
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 通过代理类调用父类中的方法
return methodProxy.invokeSuper(o,args);
}
public Object getProxy(Class clazz) {
// 设置需要创建之类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);

// 通过字节码结束创建之类实例
return enhancer.create();
}
}

测试类:

1
2
3
4
5
6
7
8
9
10
11
/**
* Created by j.tommy on 2017/9/10.
*/
public class Main {
public static void main(String[] args) {
CglibProxy cp = new CglibProxy();
UserService ius = (UserService) cp.getProxy(UserService.class);
String result = ius.request();
System.out.println("result:" + result);
}
}

更多代理模式参考:http://blog.csdn.net/yakoo5/article/details/9099133/
http://www.importnew.com/22015.html

Donny wechat
欢迎关注我的个人公众号
打赏,是超越赞的一种表达。
Show comments from Gitment