美文网首页设计模式
设计模式--代理模式

设计模式--代理模式

作者: IT雪山 | 来源:发表于2018-09-20 11:29 被阅读0次

一, 什么是代理

简单来讲,代理就是帮助【目标对象】去完成应该做,但是不想活不擅长做的事情,比如媒婆帮你找对象,黄牛帮你抢票

二, 代理模式分类

本文以Java为例,代理分为静态代理和动态代理

  • 静态代理: 就是编写一个代理类,去代理【目标对象】,比较简单。
  • 动态代理: 就是运行期间,通过反射,对【目标对象】产生一个【代理对象】(动态代理很重要,大多数框架都是通过反射进行的)动态代理起到增强的作用,这种增强符合开闭原则,不会对目标对象进行修改,而只需要扩展。
    动态代理的实现方式也分为2种,下面2中方式生成的代理都是继承Proxy(spring都用到有接口用jdk没有用cglib)
    • jdk 实现:基于接口,也就是说【目标对象】必须实现一个接口,【目标对象】和【代理对象】都实现该接口。
    • cglib实现: 可以被继承的普通类(不能是final 类)他是通过继承测方式,产生一个子类,这个子类就是代理类。

三, 静态代理实现

静态代理产生于代码编译阶段,即一旦代码运行就不可变了。下面我们来看一个例子:

public interface IPerson {
    public void doSomething();
}
public class Person implements IPerson {
    public void doSomething(){
        System.out.println("I want wo sell this house");
    }
}
public class PersonProxy {
    private IPerson iPerson;
    private final static Logger logger = LoggerFactory.getLogger(PersonProxy.class);
 
    public PersonProxy(IPerson iPerson) {
        this.iPerson = iPerson;
    }
    public void doSomething() {
        logger.info("Before Proxy");
        iPerson.doSomething();
        logger.info("After Proxy");
    }
     
    public static void main(String[] args) {
        PersonProxy personProxy = new PersonProxy(new Person());
        personProxy.doSomething();
    }
}

静态代理有很大的局限性,需要固定的类编写接口,需要实现接口的每一个函数,造成代码大量重复。

四, 动态代理模式实现之JDK

3.1用法举例:

首先定义一个接口:

public interface Subject {
    public void doSomething();
}

实现类

public class RealSubject implements Subject{

    @Override
    public void doSomething() {
        // TODO Auto-generated method stub
         System.out.println( "call doSomething()" );   
    }
}

自定义一个InvocationHandler

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ProxyHandler implements InvocationHandler{
    
    private Object realSubject;  //目标对象
    
    public ProxyHandler(Object realSubject) {
        // TODO Auto-generated constructor stub
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
               // 在目标对象的方法执行之前简单的打印一下  
               System.out.println("------------------before------------------");  
               //利用反射调用【目标对象】的方法
               Object result = method.invoke( realSubject, args); 
               // 在目标对象的方法执行之后简单的打印一下  
               System.out.println("-------------------after------------------");  
          
          return result;  

    }

}

动态代理测试类

public class Main {
    public static void main( String args[] )   
      {  
        RealSubject real = new RealSubject();  
        Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class},  new ProxyHandler(real));
        
        proxySubject.doSomething();
      }
}

以上就是动态代理jdk的实现方式,用起来非常简单,其实就是AOP的一个简单实现了,在对目标对象的方法执行之前和执行之后进行增强,Spring的AOP实现也是用了Proxy,InvocationHandler这2个东西。接下来介绍一下实现原理

3.2 实现原理

首先看一下JDK是怎样生成代理对象的。既然生成代理对象用的是Proxy 的newProxyInstance,那么我们看下源码是如何实现的

 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h); //判空

        final Class<?>[] intfs = interfaces.clone(); 
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs); //验证权限
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

其中newInstance只是调用Constructor.newInstance来构造相应的代理类实例,这里重点是看getProxyClass0这个方法的实现:

private static Class<?> getProxyClass0(ClassLoader loader,  
                                       Class<?>... interfaces) {  
    // 代理的接口数量不能超过65535(没有这种变态吧)  
    if (interfaces.length > 65535) {  
        throw new IllegalArgumentException("interface limit exceeded");  
    }  
    // JDK对代理进行了缓存,如果已经存在相应的代理类,则直接返回,否则才会通过ProxyClassFactory来创建代理  
    return proxyClassCache.get(loader, interfaces);  
}  

代理缓存是通过WeakCache实现的

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>  
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());  

ProxyClassFactory是Proxy的一个静态内部类,实现了WeakCache的内部接口BiFunction的apply方法:

private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // 所有代理类名称的前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // 用于生成代理类名字的计数器 
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
            // 生成的代理类的包名 
            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
            // 对于非公共接口,代理类的包名与接口的相同 
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
           // 这里才是真正的生成代理类的字节码的地方  
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
              // 根据二进制字节码返回相应的Class实例  
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

生成的动态代理如下:

class $Proxy0 extends Proxy{
  
   $Proxy0(InvocationHandler h){
      super(h)
   }
    void  doSomething(){
       this.h.invoke()
   }
}

它的好处理时可以为我们生成任何一个接口的代理类,并将需要增强的方法织入到任意目标函数。但它仍然具有一个局限性,就是只有实现了接口的类,才能为其实现代理。

五 动态代理模式实现之cglib

相关文章

  • Mybatis代理设计模式(Proxy)与编程实现原理

    最易懂设计模式解析适配器设计模式模板方法设计模式Mybatis多级代理 1. 认识代理模式 1.1 模式定义 给某...

  • 模板方法设计模式(Template Method)

    最易懂设计模式解析适配器设计模式Mybatis代理设计模式Mybatis多级代理 1. 认识模板方法模式 1.1 ...

  • 适配器设计模式(Adapter)

    最易懂设计模式解析模板方法设计模式Mybatis代理设计模式Mybatis多级代理 1. 认识适配器模式 1.1 ...

  • 理解java的代理模式和动态代理

    代理模式 代理模式是23种设计模式之一,属于结构型模式。代理模式是最常见也是最常用的模式之一,只不过有很多设计模式...

  • spring框架中的设计模式二

    在这篇文章中,介绍4种设计模式。结构型设计模式:代理和复合模式。行为型设计模式:策略和模板方法模式。 代理模式 面...

  • 10、结构型模式-代理设计模式

    1、加盟商来啦-你需要掌握的代理设计模式 简介:讲解代理设计模式,让代理帮你完成工作 代理设计模式(Proxy P...

  • 设计模式之代理模式

    设计模式之代理模式 10分钟看懂动态代理设计模式(升级篇)-对这篇动态代理模式的思路整理 仿JDK实现动态代理逻辑...

  • 动态代理原理解析

    注:源自于Android 一、代理模式 代理模式是java23种设计模式常用的一种设计模式。代理模式是客户端不直接...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

  • 前端设计模式

    JS设计模式一:工厂模式jS设计模式二:单例模式JS设计模式三:模块模式JS设计模式四:代理模式JS设计模式五:职...

网友评论

    本文标题:设计模式--代理模式

    本文链接:https://www.haomeiwen.com/subject/liugnftx.html