当前位置:   article > 正文

代理模式详解

代理模式详解

1.代理模式的作用

能通过代理对象间接实现对目标对象的访问,在不改变源代码的情况下对目标对象的方法进行增强。

什么是通过代理对象间接实现对目标对象的访问?

举个生活中的例子:例如你买车是通过4s店(代理对象),而不是直接去车工厂(目标对象),你只需访问4s店。

那什么不改变源代码的情况下对目标对象的方法进行增强?

还是4s店和车工厂的例子:

你去4s店买车,4s店除了卖车给你,它还有一系列的服务,例如:推荐保险,上车牌等等;

但是你去工厂就只能买车,没有其他的附加服务;也就是说4s店(代理对象)在车工厂(目标对象)的卖车基础上进行了一系列增强,但是车厂还是一样的卖车,并没有被改变。

2.代理模式的分类

代理模式分为静态代理和动态代理。

2.1静态代理

2.1.1静态代理的实现

实现步骤

1.代理类与目标类实现同一接口

2.代理对象有目标对象的引用,在同名方法中调用目标对象的方法,并在前后根据需求进行增强。

实现代码

接口代码

  1. public interface AInterface {
  2. void say();
  3. }

目标类代码

  1. public class AInterfaceImpl implements AInterface{
  2. @Override
  3. public void rap() {
  4. System.out.println("rap");
  5. }
  6. @Override
  7. public void basketball() {
  8. System.out.println("篮球");
  9. }
  10. }

代理类代码

  1. public class AStaticProxy implements AInterface{
  2. //目标对象
  3. private AInterface aInterface;
  4. //注入目标对象
  5. public AStaticProxy(AInterface aInterface) {
  6. this.aInterface = aInterface;
  7. }
  8. @Override
  9. public void rap() {
  10. System.out.println("前置增强");
  11. aInterface.rap();
  12. System.out.println("后置增强");
  13. }
  14. @Override
  15. public void basketball() {
  16. System.out.println("前置增强");
  17. aInterface.basketball();
  18. System.out.println("后置增强");
  19. }
  20. }

2.2.1静态代理的缺点

1.只能代理某一类接口

2.若进行多次增强,可能代理类暴增

3.修改接口,要同时维护目标类和代理类

4.若是代理类的增强逻辑一致,可能造成大量重复代码

5.增强代码和目标方法硬编码

2.2动态代理

针对静态代理的缺点,我们可能观察到,许多静态代理的缺点都来自于代理类;

如果我们将代理类干掉,就能解决静态代理的大部分缺点。

可是在静态代理中我们通过代理类的构造方法才能得到代理对象,若是没有代理类,怎么创建代理对象呢?

我们先观察一下到底静态代理是如何通过代理类得到代理对象的,这就涉及到java代码的运行原理了。

           编译                         类加载                             反射得到构造方法

代理类-------> 代理类.class---------->   JVM中的Class------------------------>创建得到代理对象

那么动态代理没有代理类,只能通过接口.class,很明显会在得到构造方法这里卡住,因为接口没有构造方法。

那么有没有办法能够既有接口的方法信息又有构造方法呢?

答案是:通过Proxy类的getProxyClass(classLoader,Interface)方法,我们只需传入将接口的信息作为参数传入,就能得到一个既有接口信息又有构造方法的Class对象,通过该Class得到构造方法,我们就能创建代理对象了。

那为什么Proxy类的getProxyClass方法那么神奇?

这里尚且不做深入了解,你可以理解为它就是 想办法把接口Class里面的方法信息拼接一个构造方法得到新的Class。

2.2.1动态代理的实现

实现步骤

1.编写一个工具类,里面提供一个静态方法getProxy(Object target,InvocationHandler i)

2.在getProxy()方法中,通过Proxy类的静态方法getProxyClass(classLoader,Interface),传入目标对象接口的参数,然后得到新的代理Class对象

3.通过代理Class对象调用getDeclaredConstructor(InvocationHandler.class)方法,传入Invocationhandler的Class对象得到构造方法对象

4.通过构造方法对象的newInstance(InvocationHandler)传入Invocationhandler对象创建得到代理对象

实现代码

接口代码

  1. public interface AInterface {
  2. void say();
  3. }

目标类代码

  1. public class AInterfaceImpl implements AInterface{
  2. @Override
  3. public void rap() {
  4. System.out.println("rap");
  5. }
  6. @Override
  7. public void basketball() {
  8. System.out.println("篮球");
  9. }
  10. }

代理工具类的代码

  1. public class MyProxy {
  2. /**
  3. * 获取代理对象
  4. * @param target 目标对象
  5. * @param invocationHandler 代理处理器
  6. * @return
  7. * @throws Exception
  8. */
  9. public static Object getProxy(Object target, InvocationHandler invocationHandler) throws Exception{
  10. //获得目标对象的Class对象
  11. Class clazz = target.getClass();
  12. //根据目标对象的Class对象得到代理对象的Class
  13. Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), clazz.getInterfaces());
  14. //根据代理对象Class获得代理对象的构造器
  15. Constructor declaredConstructor = proxyClass.getDeclaredConstructor(InvocationHandler.class);
  16. //根据代理对象的构造器创建代理对象
  17. Object o = declaredConstructor.newInstance(invocationHandler);
  18. //返回得到的代理对象
  19. return o;
  20. }
  21. }

得到的代理对象的结构是怎么样的?

代理对象大致结构:
  1. public class MProxy implements AInterface{
  2. private InvocationHandler ih;
  3. public MProxy(InvocationHandler ih) {
  4. this.ih = ih;
  5. }
  6. @Override
  7. public void rap() {
  8. ih.invoke();
  9. }
  10. @Override
  11. public void basketball() {
  12. ih.invoke();
  13. }
  14. }

2.2.2动态代理的缺点

只剩下增强代码和目标方法硬编码

静态代理的缺点有:

1.只能代理某一类接口

2.若进行多次增强,可能代理类暴增

3.修改接口,要同时维护目标类和代理类

4.若是代理类的增强逻辑一致,可能造成大量重复代码

5.增强代码和目标方法硬编码

动态代理如何优化的

对于静态代理的缺点1,动态代理只传入目标对象,目标对象可以是任意接口的,所以解决了

对于静态代理的缺点2、3、4,动态代理没有代理类,也解决了

但是对于静态代理的缺点5增强代码和目标方法硬编码,在动态代理的invoke方法

中还是没能避免,这个缺点在后来的aop(面向切面编程才得以解决),它将方法的逻辑进行拆分,无侵入式的对方法进行增强。

2.2.3动态代理的拓展

本文章的动态代理是JDK根据接口实现的,此外还有第三方的动态代理,如cglib,它实现的原理同JDK不同,它是基于继承来实现的,子类继承父类重写父类方法实现的增强

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号