Design pattern--the implementation and principle analysis of proxy mode

Source: Internet
Author: User
Tags abstract arrays constructor hash object object reflection static class throwable
Agent Mode Introduction

The proxy mode, also known as the delegate mode, is one of the most important design patterns. Agents in our daily life is actually very common, for programmers most often contact is the use of proxy Internet access, connect proxy server address, you can easily explore the world's network; Let colleagues help bring rice is also a proxy way. The essence of proxy mode is entrustment. definition

Provides a proxy for other objects to control access to this object. Usage Scenarios

When there is difficulty in accessing a property or accessing an object directly, it can be accessed indirectly through a proxy object, in order to ensure the transparency of client use, the delegate object and the proxy object need to implement the same interface. UML class Diagram

Role Description Subject: Abstract Theme class
The primary responsibility of this class is to declare a common interface method between a real topic and a proxy, which can be either an abstract class or an interface. Realsubject: Real Theme class .
The class is also called a delegated class or a proxy class that defines the real object represented by the proxy, which executes the specific business logic method, while the client indirectly invokes the method defined in the real topic class through the proxy class. proxysubject: proxy class
This class is also known as a delegate class or proxy class, which holds a reference to a real topic class and invokes the corresponding interface method execution in the interface method implemented by the real topic class, which acts as an agent. Client Customer Class
The type of the proxy class to use. Simple Implementation

The following to a purchase of life cases to show the implementation of the proxy model, life in the way of purchasing is very common, do the purchasing of people to help customers buy those customers themselves are not easy to buy goods and charge a certain commission, this is a typical example of proxy mode.

Shopping interface Ishop, define shopping behavior.

/**
 * Shopping Interface * * Public
interface Ishop {
    /**
     * Buy things *
    /void Buy ();
}

The customer class implements the shopping interface.

/**
 * Customer class implements the shopping interface
 *
/public class customer implements Ishop {public
    void buy () {
        System.out.println ("Bought a Nexus phone");}
}

Purchasing Merchant Seller class, realize the shopping interface and hold a reference by the agent.

/**
 * Purchasing Merchant
 *
/public class Seller implements Ishop {
    //holding a proxy reference
    private ishop shop;

    Public Seller (Ishop shop) {

        this.shop = shop;
    }


    public void Buy () {
        shop.buy ();
    }
}

Test class

/**
 * Client Test class
 *
/public class Client {public
    static void Main (string[] args) {
        //static proxy
        Create a Customer object
        ishop customer = new Customer ();
        Create a Shopper object
        Seller Seller = new Seller (customer);
        Make a purchase Operation
        Seller.buy ();
    }
}

Run results

Bought a Nexus phone

In fact, it is also very simple, in the implementation of the above proxy mode, is to use the proxy class to hold the proxy class of the Reference object, the indirect invocation of the proxy method. Proxy Mode Classification

In addition to the above proxy mode, the proxy mode has other implementation methods, divided into the following two kinds. Static proxy

Static proxy as shown in the example above, the agent's code is generated by the programmer itself or through some automated tools to generate fixed code and then compile it, that is, before our code is run, the class compiler file of the proxy classes already exists. Dynamic Agent

Dynamic proxies, in contrast to static proxies, dynamically generate proxy objects through a reflection mechanism, which means that we do not need to know the agent at all in the code phase, and we will decide at the execution stage.

The implementation of the dynamic proxy can be achieved by means of a JDK, or by using a third-party bytecode generation tool, Cglib, and so on. how JDK is implemented

The JDK also gives us a handy dynamic proxy interface Invocationhandler, which implements the interface needs to rewrite its invocation method invoke.

public class Dynamicproxy implements Invocationhandler {
    @Override public
    object Invoke (object proxy, Method method, object[] args) throws Throwable {
        return null;
    }
}

Here, we invoke the specific proxy method mainly through the Invoke method. Dynamic proxies can make our code logic more concise, but first we need to refine the proxy class.

public class Dynamicproxy implements Invocationhandler {

    private Object obj;//The proxy class references public

    dynamicproxy ( Object obj) {
        this.obj = obj;
    }

    @Override Public
    object Invoke (Object proxy, method, object[] args) throws Throwable {
        //method
        to invoke the proxy class object Object result = Method.invoke (obj, args);
        return result;
    }
}

As shown in the preceding code, we declare a reference to an object that will point to the proxy class, and the specific method of invoking the proxy class is executed in the Invoke method, which is much simpler. That is to say, our original work by the proxy class is now handled by Invocationhandler, no longer need to care about who is acting. Let's modify the code of the static proxy above.

/**
 * Dynamic Proxy implementation class */public class
Dynamicproxy implements Invocationhandler {


    Private Object obj;//proxy class reference Public

    dynamicproxy (Object obj) {
        this.obj = obj;
    }

    /**
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws throwable
    * * public object invoke (object proxy, Method method, object[] args) throws Throwable {
        //method
        to invoke the proxy class object System.out.println ("Prior to Execution");
        Object result = Method.invoke (obj, args);
        System.out.println ("after Execution");
        return result;
    }   
}

Test class

Import Java.lang.reflect.Proxy;

/**
 * Client class
 *
/public class Client {public
    static void Main (string[] args) {
         // System.getproperties (). Put ("Sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        Dynamic Agent
        //Constructs a proxy class object
        ishop customer = new Customer ();
        Dynamicproxy proxy = new Dynamicproxy (customer);
        Gets the ClassLoader
        ClassLoader loader = Customer.getclass () of the proxy class. getClassLoader ();
        Dynamically constructs a proxy class
        ishop shop = (ishop) proxy.newproxyinstance (loader, new Class[]{ishop.class}, proxy);
        Call Method
        shop.buy ();
    }
}

Run results

Executed before
buying a Nexus phone
after execution

As you can see, we did not take advantage of the original proxy class seller, but instead used the dynamic proxy method to invoke Proxy.newproxyinstance () to dynamically generate a proxy object and successfully executed the method. the implementation principle of JDK dynamic agent

Follow the Proxy.newproxyinstance () method of the source code, you can see the program has been validated, optimized, cached, synchronized, generated bytecode, display class loading and other operations.
The following is the source of the proxy class, based on Sun JDK1.7

Package java.lang.reflect;
Import java.lang.ref.WeakReference;
Import java.lang.reflect.WeakCache.BiFunction;
Import Java.security.AccessController;
Import java.security.Permission;
Import java.security.PrivilegedAction;
Import Java.util.Arrays;
Import Java.util.IdentityHashMap;
Import Java.util.Map;
Import Java.util.concurrent.atomic.AtomicLong;
Import Sun.misc.ProxyGenerator;
Import sun.reflect.CallerSensitive;
Import sun.reflect.Reflection;
Import Sun.reflect.misc.ReflectUtil;

Import sun.security.util.SecurityConstants; public class Proxy implements java.io.Serializable {private static final long Serialversionuid = 222256805668662379


    7L;

 constructor parameter type for proxy class private static final class<?>[] Constructorparams = {Invocationhandler.class}; Used to maintain the class loader object to its corresponding proxy class cache private static Final Weakcache<classloader, class<?>[], class<?>> Pro

    Xyclasscache = new Weakcache<> (new Keyfactory (), New Proxyclassfactory ()); The associated calling processor citedwith protected Invocationhandler h; The constructor is declared private, and the private Proxy () {}///is not instantiated because the constructor is never called directly inside the proxy, so protected means that only subclasses can invoke protected Pro
        XY (Invocationhandler h) {Donewinstancecheck ();
    This.h = h;
        }//proxy class Access control helper class private static class Proxyaccesshelper {//the permission is implementation specific.
        Static final Permission proxy_permission = new Reflectpermission ("Proxyconstructornewinstance"); These system properties is defined to provide a short-term//workaround if customers need to disable the new
        Security checks.
        Static Final Boolean allownewinstance;
        Static Final Boolean allownullloader;
            static {allownewinstance = Getbooleanproperty ("sun.reflect.proxy.allowsNewInstance");
        Allownullloader = Getbooleanproperty ("Sun.reflect.proxy.allowsNullLoader");
         } private static Boolean Getbooleanproperty (final String key) {   String s = accesscontroller.doprivileged (new privilegedaction<string> () {public String run () {
                return System.getproperty (key);
            }
            });
        return boolean.valueof (s); } Static Boolean Needsnewinstancecheck (Class<?> proxyclass) {if (! Proxy.isproxyclass (proxyclass) | |
            Allownewinstance) {return false; } if (Reflectutil.isnonpublicproxyclass (Proxyclass)) {for (class<?> intf:proxyclass. Getinterfaces ()) {if (!
                    Modifier.ispublic (Intf.getmodifiers ())) {return true;
        }}} return false; }}//Access check is performed on the proxy class that implements any non-public type interface, and if Security Manager is present, the caller does not have permission to call and throws a security exception private void Donewinstanceche
        CK () {SecurityManager sm = System.getsecuritymanager (); Class<?> Proxyclass =This.getclass (); if (SM! = null && Proxyaccesshelper.needsnewinstancecheck (proxyclass)) {try {Sm.chec
            Kpermission (proxyaccesshelper.proxy_permission);
                        } catch (SecurityException e) {throw new SecurityException ("not allowed to construct a Proxy"
            + "instance that implements a Non-public interface", e); }}}//Returns the Java.lang.Class object of the proxy class and provides it with a class loader and an array of interfaces @CallerSensitive public static class<?> GETP Roxyclass (ClassLoader loader, class<?> .... interfaces) throws Illega
        largumentexception {final class<?>[] Intfs = Interfaces.clone ();
        Final SecurityManager sm = System.getsecuritymanager ();
        if (SM! = null) {checkproxyaccess (Reflection.getcallerclass (), loader, intfs);
    } return GetProxyClass0 (loader, intfs); } private static void CheckpRoxyaccess (class<?> caller, ClassLoader Loader,
        Class<?&gt interfaces) {SecurityManager SM = System.getsecuritymanager ();
            if (SM! = null) {ClassLoader CCL = Caller.getclassloader (); if (loader = = NULL && CCL! = null) {if (! 
                Proxyaccesshelper.allownullloader) {sm.checkpermission (securityconstants.get_classloader_permission);
        }} reflectutil.checkproxypackageaccess (CCL, interfaces); }}//Generates a proxy class that must be called checkproxyaccess for permission check before calling this method. private static Class<?> GetProxyClass0 (ClassLoader l
        Oader, Class<?&gt, ... interfaces) {//throws an exception if the target class implements more than 65,535 interfaces
        if (Interfaces.length > 65535) {throw new IllegalArgumentException ("Interface limit exceeded"); }


        //If the corresponding proxy class has been found in the cache, the cache is obtained directly, otherwise the Proxyclassfactory method will be called to create a new proxy class return Proxyclasscache.get (loader, interfaces);


     }//This key value is used for proxy classes that do not implement the interface private static final Object key0 = new Object (); This key value is used for proxy classes that implement 1 interfaces private static final class Key1 extends weakreference<class<?>> {private F

        inal int hash;
            Key1 (class<?> intf) {super (intf);
        This.hash = Intf.hashcode ();
        } @Override public int hashcode () {return hash;
            } @Override public boolean equals (Object obj) {class<?> intf;
                   return this = = obj | | Obj! = null && obj.getclass () = = Key1.class && (intf = Get ())! = nul
        L && intf = = ((Key1) obj). get (); }}//This key value is used for proxy classes that implement two interfaces private static final class Key2 extends WEAKREFERENCE&LT;CLASS&LT;?&Gt;> {private final int hash;

        Private final weakreference<class<?>> Ref2;
            Key2 (class<?> intf1, class<?> intf2) {super (INTF1);
            hash = * Intf1.hashcode () + Intf2.hashcode ();
        Ref2 = new weakreference<class<?>> (INTF2);
        } @Override public int hashcode () {return hash;
            } @Override public boolean equals (Object obj) {class<?> intf1, INTF2;
                   return this = = obj | | Obj! = null && obj.getclass () = = Key2.class && (INTF1 = Get ())! = Nu ll && INTF1 = = ((Key2) obj). Get () && (INTF2 = Ref2.get ())! = null &A
        mp;& INTF2 = = ((Key2) obj). Ref2.get (); }}//This key value is used for proxy classes that implement any interface (this is only used for proxy classes that implement 3 or more interfaces) private static final class KeyX {Private final int hash;

        Private final weakreference<class<?>>[] refs;
            KeyX (class<?>[] interfaces) {hash = Arrays.hashcode (interfaces);
            Refs = new Weakreference[interfaces.length];
            for (int i = 0; i < interfaces.length; i++) {refs[i] = new WeakReference (interfaces[i]);
        }} @Override public int hashcode () {return hash;
                   } @Override public boolean equals (Object obj) {return this = = obj | | Obj! = null && obj.getclass () = = Keyx.class && equals (refs, ((KeyX)
        obj). refs);
                                      } private static Boolean Equals (Weakreference<class<?>>[] REFS1, Weakreference<class<?>>[] refs2) {if (refs1.length! = refs2.length) {return FA
            Lse
            }for (int i = 0; i < refs1.length; i++) {class<?> intf = Refs1[i].get ();
                if (intf = = NULL | | intf! = refs2[i].get ()) {return false;
        }} return true; }}/** * A function that maps an array of interfaces to an optimal key where * Class objects represent
     ING interfaces is weakly referenced. *//used to generate a set of interface to an optimal key mapping between map private static final class Keyfactory implements Bifunction<class Loader, class<?>[], object> {@Override public Object apply (ClassLoader ClassLoader, class&lt ;? >[] interfaces) {switch (interfaces.length) {case 1:return new Key1 (Interfaces[0]);
                Frequent use case 2:return new Key2 (Interfaces[0], interfaces[1]);
                Case 0:return Key0;
            Default:return new KeyX (interfaces); }}}//This classGenerates and defines and returns a proxy class based on the given ClassLoader and interface array private static final class Proxyclassfactory implements BIFUNCTION&LT;CLA
        Ssloader, class<?>[], class<?>> {//prefix for all proxy class names//class name prefix of all proxy classes

        private static final String Proxyclassnameprefix = "$Proxy"; Next number to uses for generation of unique proxy class names//using atomic atomic variable to generate the next unique surrogate class name private Stati

        C final Atomiclong nextuniquenumber = new Atomiclong (); @Override public class<?> Apply (ClassLoader loader, class<?>[] interfaces) {Map<class
            <?&gt, boolean> interfaceset = new identityhashmap<> (interfaces.length); for (class<?> intf:interfaces) {/* * Verify that the Class loader resolves the n
                 Ame 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) {T
                Hrow New IllegalArgumentException (intf + "isn't visible from class loader");
                 }/* * Verify that the Class object actually represents an * interface. */if (!interfaceclass.isinterface ()) {throw new Illegalargumentexce
                Ption (Interfaceclass.getname () + "isn't an interface");
                 }/* * Verify that this interface are not a duplicate. */if (Interfaceset.put (Interfaceclass, boolean.true)! = null) {throw new Illegalargu Mentexception ("Repeated interface:" + INTERFACECLASS.GEtname ());     }} String proxypkg = null; Package to define proxy class in/* * Record the package of a non-public proxy interface so t  Hat the * proxy class is defined in the same package.
             Verify that * All Non-public proxy interfaces is in the same package.
                */for (class<?> intf:interfaces) {int flags = Intf.getmodifiers (); if (!
                    Modifier.ispublic (Flags)) {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 in Terfaces, use com.sun.proxy package proxypkg =

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.