设计模式之代理模式案例详解

  • 格式: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,如果取不到资源,再到公⽹或者数据库取,然后缓存。

远程代理:远程对象的本地代表,通过它可以把远程对象当本地对象来调⽤。远程代理通过⽹络和真正的远程对象沟通信息。

同步代理:主要使⽤在多线程编程中,完成多线程间同步⼯作。