设计模式之代理模式案例详解
- 格式:pdf
- 大小:126.88 KB
- 文档页数:4
设计模式之代理模式案例详解
代理模式是指为⼀个对象提供⼀个替⾝,以控制对这个对象的访问。即通过代理对象访问⽬标对象,这样做的好处是,可以在⽬标对象实现
在基础上,增强额外的功能操作,即扩展⽬标对象的功能。
被代理的对象可以是远程对象、创建开销⼤的对象或需要安全控制的对象。
代理模式有不同的形式,主要有两种:动态代理和静态代理,动态代理有JDK代理和CGLIB代理两种。代理模式⽰意图:
静态代理介绍
静态代理在使⽤时,需要定义接⼝或者⽗类,被代理对象(即⽬标对象)与代理对象⼀起实现相同的接⼝或者是继承相同⽗类。
应⽤实例具体要求:定义⼀个接⼝:ITeacherDao;⽬标对象TeacherDao实现接⼝ITeacherDao;使⽤静态代理⽅式,就需要在代理对象TeacherDaoProxy中也实现ITeacherDao;调⽤的时候通过调⽤代理对象的⽅法来调⽤⽬标对象;
特别提醒:代理对象与⽬标对象要实现相同的接⼝,然后通过调⽤相同的⽅法来调⽤⽬标对象的⽅法。思路分析
代码实现
1public interface ITeacherDao {
2 void teach();//授课的⽅法
3}
1//被代理对象
2public class TeacherDao implements ITeacherDao {
3 @Override
4 public void teach() {
5 System.out.println("⽼师授课中...");
6 }
7}
1//代理对象
2public class TeacherDaoProxy implements ITeacherDao {
3
4 private ITeacherDao iTeacherDao;
5
6 public TeacherDaoProxy(ITeacherDao iTeacherDao){
7 this.iTeacherDao=iTeacherDao;
8 }
9
10 @Override
11 public void teach() {
12 System.out.println("⽼师备课");
13 iTeacherDao.teach();
14 System.out.println("⽼师结束讲课");
15 }
16}
1public class Client { 2 public static void main(String[] args) {
3 //创建被代理对象(⽬标对象)
4 TeacherDao teacherDao = new TeacherDao();
5 //创建代理对象,同时将被代理对象传递给代理对象 6 TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
7 //通过代理对象,调⽤到被代理对象的⽅法
8 teacherDaoProxy.teach();
9 }
10}
注意事项
优点:在不修改⽬标对象的功能前提下,能通过代理对象对⽬标功能扩展。
缺点:因为代理对象需要与⽬标对象实现⼀样的接⼝,所以会有很多代理类。
⼀旦接⼝增加⽅法,⽬标对象与代理对象都要维护。JDK代理
介绍
代理对象不需要实现接⼝,但是⽬标对象要实现接⼝,否则不能⽤动态代理。
代理对象的⽣成,是利⽤JDK的API,动态的在内存中构建代理对象。
应⽤实例
将前⾯的静态代理改成JDK动态代理。
代码实现
1public interface ITeacherDao {
2
3 void teach();
4}
1public class TeacherDao implements ITeacherDao {
2 @Override
3 public void teach() {
4 System.out.println("⽼师正在授课...");
5 }
6}
1import java.lang.reflect.InvocationHandler;
2import java.lang.reflect.Method;
3import java.lang.reflect.Proxy;
4
5public class ProxyFactory {
6
7 private Object target;//⽬标对象
8
9 public ProxyFactory(Object target) {
10 this.target = target;
11 }
12
13 //给⽬标对象⽣成⼀个代理对象
14 public Object getProxyInstance() {
15
16 /**17 * newProxyInstance⽅法参数说明
18 * 第⼀个参数:指定当前⽬标对象使⽤的类加载器;
19 * 第⼆个参数:⽬标对象实现的接⼝类型;
20 * 第三个参数:事件处理,执⾏⽬标对象的⽅式时,会触发事件处理器⽅法
21 */
22 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
23 target.getClass().getInterfaces(),
24 new InvocationHandler() {
25 @Override
26 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
27 System.out.println("⽼师备课");
28 //反射机制调⽤⽬标对象的⽅法
29 Object invoke = method.invoke(target, args);
30 System.out.println("⽼师讲完课了");
31 return invoke;
32 }
33 }
34 );
35 }
36}
CGLIB代理介绍
静态代理和JDK代理都要求⽬标对象是实现⼀个接⼝,但是有时候⽬标对象只是⼀个单独的对象,并没有实现任何的接⼝,这个时候可使⽤
⽬标对象⼦类来实现代理,这就是CGLIB代理。CGLIB包的底层是通过使⽤字节码处理框架ASM来转换字节码并⽣成新的类。
CGLIB代理也叫作⼦类代理,它是在内存中构建⼀个⼦类对象从⽽实现对⽬标对象功能扩展。
CGLIB是⼀个强⼤的⾼性能的代码⽣成包,它可以在运⾏期扩展Java类与实现Java接⼝,它⼴泛的被许多AOP的框架使⽤,例如Spring
AOP,实现⽅法拦截。
在AOP编程中如何选择代理模式:如果⽬标对象需要实现接⼝,⽤JDK代理;如果⽬标对象不需要实现接⼝,⽤CGLIB代理。
注意事项
需要引⼊cglib的jar⽂件。
在内存中动态构建⼦类,注意代理的类不能为final,否则报错。
⽬标对象的⽅法如果为final/static,那么就不会被拦截,即不会执⾏⽬标对象额外的业务⽅法。
思路分析
代码实现
1public class TeacherDao {
2
3 public void teach(){
4 System.out.println("⽼师授课中...");
5 }
6}
1import net.sf.cglib.proxy.Enhancer;
2import net.sf.cglib.proxy.MethodInterceptor;
3import net.sf.cglib.proxy.MethodProxy;
4import java.lang.reflect.Method;
5
6public class ProxyFactory implements MethodInterceptor {
7
8 private Object target;//维护⼀个⽬标对象
9
10 //构造器,传⼊被代理对象
11 public ProxyFactory(Object target){
12 this.target=target;
13 }
14
15 //返回⼀个代理对象
16 public Object getProxyInstance(){
17 //1、创建⼀个⼯具类
18 Enhancer enhancer = new Enhancer();
19 //2、设置⽗类
20 enhancer.setSuperclass(target.getClass());
21 //3、设置回调函数
22 enhancer.setCallback(this);
23 //4、创建⼦类对象,即代理对象
24 return enhancer.create();
25 }26
27 @Override
28 public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
29 System.out.println("⽼师备课");
30 Object invoke = method.invoke(target, args);
31 System.out.println("⽼师讲完课了");
32 return invoke;
33 }
34}
1public class Client {
2 public static void main(String[] args) {
3 //创建⽬标对象
4 TeacherDao teacherDao = new TeacherDao();
5 //创建代理对象,返回被代理的⽬标对象(必须强制类型转换)
6 TeacherDao proxyInstance = (TeacherDao) new ProxyFactory(teacherDao).getProxyInstance();
7 proxyInstance.teach();
8 }
9}
防⽕墙代理:内⽹通过代理穿透防⽕墙,实现对公⽹的访问。
缓存代理:⽐如,当请求图⽚⽂件等资源时,先到缓存代理取,如果取到资源则ok,如果取不到资源,再到公⽹或者数据库取,然后缓存。
远程代理:远程对象的本地代表,通过它可以把远程对象当本地对象来调⽤。远程代理通过⽹络和真正的远程对象沟通信息。
同步代理:主要使⽤在多线程编程中,完成多线程间同步⼯作。