Design pattern Three: Proxy mode--the way the JDK is implemented

Source: Internet
Author: User
Tags getmessage iterable throwable
Design pattern Three: Proxy mode--Introduction to how JDK is implemented

Proxy mode is one of the behavioral patterns, which controls access to other objects and acts as an intermediary.

Agent Mode core role: Real role, Agent role;

There are two kinds of static agent and dynamic agent according to different implementation mode.

Intention

Controls access to other objects.

Class diagram

Realize

The JDK comes with the implementation of proxy, we first use the JDK API to demonstrate how the agent is used, and then explore the implementation of the principle of the proxy, and to implement the proxy itself.

Use of the JDK proxy class: ( InvocationHandler, Proxy)
    使用JDK实现的代理代码如下, 先定义业务接口`Car`,然后实现该接口`QQCar`,实现类即为真实角色. 继续定义代理类`Agent`,代理类需要实现接口`InvocationHandler`的`invoke()`方法, 最后是调用;    注意代理类使用了`Proxy.newProxyInstance()`方法动态生成代理对象, 在稍后手写代码时我们将参考本方法定义我们自己的实现方式.
/** * 汽车接口,定义业务规范 */public interface Car {    void sale();}
 /** * Interface Car specific implementation, is the real role in the proxy mode */public class Qqcar implements Car {public void sale () {    System.out.println ("sold a QQ"); }}
 /** * Brokerage company, or reseller */public class Agent implements Invocationhandler {private car car; /** * Returns the proxy object, receives the proxy object * @param car * @return * @throws Exception */public object getinstance (car CA        R) throws Exception {This.car=car;        Class clazz = Car.getclass ();        Look at the specific type of the agent before and after System.out.println ("type of Agent before object" +car.getclass (). GetName ());        Object obj = proxy.newproxyinstance (Clazz.getclassloader (), clazz.getinterfaces (), this);        Look at the specific type of the agent before and after System.out.println ("Agent after object type changed to" +obj.getclass (). GetName ());    return obj; The public object invoke (object proxy, Method method, object[] args) throws Throwable {System.out.println ("Agent        Find some costumers ");        This.car.sale ();        Method.invoke (This.car, args);        System.out.println ("Agent saled the Car");    return null; }}
try {    Car car = (Car) new Agent().getInstance(new QQCar());    car.sale();}catch (Exception e){    e.printStackTrace();}

Summarize the JDK principle as follows:

    1. Get a reference to a real role object and get its interface
    2. Proxy generates an agent class and implements the method of the interface
    3. Get a reference to the object being proxied
    4. Class byte code for dynamically generated proxy classes
    5. Compile load
Handwriting Implementation Proxy

To implement the JDK's proxy mode, we first have to understand how the JDK proxy is implemented, debug and view the source code can know the JDK generated a $Proxy0 type, we also print the type name to the console. If you can dynamically generate, compile, and load this class into memory, We can implement the proxy on our own.

    1. First get $Proxy0 the code, for us to generate the proxy class after the source of the reference
//生产接口Car对应的代理类class文件并保存到文件byte[] data = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Car.class});FileOutputStream outputStream = new FileOutputStream("E:\\design-patterns\\src\\main\\java\\com\\xlx\\pattern\\proxy\\jdk\\$Proxy0.class");outputStream.write(data);outputStream.close();

The

Generated $proxy0.class file has the following anti-compilation code, which can be seen to implement the car interface.

Source code recreated from a. class file by IntelliJ idea//(powered by Fernflower Decompiler)//import Com.xlx.patter N.proxy.jdk.car;import Java.lang.reflect.invocationhandler;import Java.lang.reflect.method;import Java.lang.reflect.proxy;import java.lang.reflect.undeclaredthrowableexception;public Final class $Proxy 0 extends    Proxy implements Car {private static Method M1;    private static Method m2;    private static Method m3;    private static Method M0;    Public $Proxy 0 (Invocationhandler var1) throws {super (VAR1); Public final Boolean equals (Object var1) throws {try {return (Boolean) Super.h.invoke (this, M1, n        EW object[]{var1}); } catch (RuntimeException |        Error var3) {throw var3;        } catch (Throwable var4) {throw new undeclaredthrowableexception (VAR4); }} public final String toString () throws {try {return (String) Super.h.invoke (This, M2, (Object        []) null); }catch (RuntimeException |        Error var2) {throw var2;        } catch (Throwable var3) {throw new undeclaredthrowableexception (VAR3);        }} public final void sale () throws {try {Super.h.invoke (this, M3, (object[]) null); } catch (RuntimeException |        Error var2) {throw var2;        } catch (Throwable var3) {throw new undeclaredthrowableexception (VAR3); }} public final int hashcode () throws {try {return (Integer) Super.h.invoke (This, M0, (object[]        ) null); } catch (RuntimeException |        Error var2) {throw var2;        } catch (Throwable var3) {throw new undeclaredthrowableexception (VAR3); }} static {try {m1 = Class.forName ("Java.lang.Object"). GetMethod ("Equals", Class.forName ("java. Lang.            Object "));            M2 = Class.forName ("Java.lang.Object"). GetMethod ("toString"); M3 = Class.forName ("Com.xlx.pattern.Proxy.jdk.Car "). GetMethod (" Sale ");        M0 = Class.forName ("Java.lang.Object"). GetMethod ("Hashcode");        } catch (Nosuchmethodexception var2) {throw new Nosuchmethoderror (Var2.getmessage ());        } catch (ClassNotFoundException var3) {throw new Noclassdeffounderror (Var3.getmessage ()); }    }}
    1. Refer to the implementation of the JDK, we define separately,,, MyClassLoader MyInvocationHandler MyProxy respectively correspondence ClassLoader , InvocationHandler , Proxy ;
      Where the interface MyInvocationHandler code is as follows:
/** * 代理类需要实现该接口 */public interface MyInvocationHandler {    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;}
    1. Defining the proxy class corresponds to what MyAgent we defined when using the JDK Agent , but the getInstance() method implementation is all changed to a custom class in 2, implementing the interface defined in 2
/** * 代理类 */public class MyAgent implements MyInvocationHandler {    private Car car;    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("Agent find some costumers");        //this.car.sale();        method.invoke(this.car,args);        System.out.println("Agent saled the car");        return null;    }    public Object getInstance(Car car) throws Exception {        this.car=car;        Class clazz = car.getClass();        Object obj = MyProxy.newProxyInstance(new MyClassLoader(),clazz.getInterfaces(),this);        return obj;    }}
    1. MyProxymethods for generating proxy objects in the implementationnewProxyInstance()
      In particular, it is divided into the following steps:

       1. 定义动态代理类的源码 2. 保存源码文件到磁盘 3. 编译源码文件为.class文件 4. 加载.class字节码到内存 (具体实现见5.实现MyClassLoader)) 5. 返回代理对象
/** * Generate proxy object code, the specific principle of proxy here embodies */public class Myproxy {private static final String ln = "\ r \ n"; public static Object newproxyinstance (Myclassloader loader, class<?>[] interfaces, Myinvocationhandler h) {F        Ile f = null;            try {//First step: Generate source code String src = generatesrc (interfaces[0]);            Step two: Save the generated source file String FilePath = MyProxy.class.getResource (""). GetPath ();            f = new File (FilePath + "/$Proxy 0.java");            FileWriter writer = new FileWriter (f);            Writer.write (SRC);            Writer.flush ();            Writer.close ();            Step three: Compile and build the. class file Javacompiler Compliler = Toolprovider.getsystemjavacompiler ();            Standardjavafilemanager manager = Compliler.getstandardfilemanager (null, NULL, NULL);            Iterable iterable = manager.getjavafileobjects (f);          Javacompiler.compilationtask task = Compliler.gettask (NULL, manager, NULL, NULL, NULL, iterable);  ((javacompiler.compilationtask) Task). Call ();            Manager.close ();            Fourth step: Load the class bytecode into memory (Myclassloader class implementation) class Proxyclass = Loader.findclass ("$Proxy 0");            Fifth step: Return the proxy object Constructor Constructor = Proxyclass.getconstructor (Myinvocationhandler.class);        return constructor.newinstance (h);        } catch (Exception e) {e.printstacktrace ();            } finally {if (null! = f) {f.delete ();    }} return null; }/** * Generate source code method * * @param interfaces for demonstration, press an interface to process * @return */private static String GENERATESR        C (class<?> interfaces) {stringbuffer src = new StringBuffer ();        Src.append ("package com.xlx.pattern.proxy.my;" + ln);        Src.append ("Import java.lang.reflect.Method;" + ln);        Src.append ("public class $Proxy 0 extends myproxy implements" + interfaces.getname () + "{" + ln); Src.append ("Myinvocationhandler h;" + LN);        Src.append ("Public $Proxy 0 (Myinvocationhandler h) {" + ln);        Src.append ("this.h=h;" + ln);        Src.append ("}" + ln); Loop definition method with the same name as the method of the proxy class for (method M:interfaces.getmethods ()) {Src.append ("public" + M.getreturntype ()            . GetName () + "" + m.getname () + "() {" + ln);            Src.append ("try{" + ln);            Src.append ("Method m =" + interfaces.getname () + ". Class.getmethod (\" "+ m.getname () +" \ ", New class[]{});" + ln ";            Src.append ("This.h.invoke (This,m,null);" + ln);            Src.append ("}catch (Throwable e) {e.printstacktrace ();}" + ln);        Src.append ("}" + ln);        } src.append ("}" + ln);    return src.tostring (); }}
    1. implements the Findclass () method for Myclassloader , and ultimately by the parent class Classloader.defineclass () method to load, complete the final puzzle
/** * Code generation, compilation, reloading into memory * class loader, using ClassLoader */public class Myclassloader extends classloader{File basepath;        Public Myclassloader () {String basepath = MyClassLoader.class.getResource (""). GetPath ();    This.basepath = new File (basepath); } @Override Public class<?> findclass (string name) throws classnotfoundexception{string className = My ClassLoader.class.getPackage (). GetName () + "."        +name;            if (null!=basepath) {file Classfile = new File (basepath,name.replaceall ("\ \", "/") + ". Class");                if (classfile.exists ()) {fileinputstream in = null;                Bytearrayoutputstream out= null;                    try {in = new FileInputStream (classfile);                    out = new Bytearrayoutputstream ();                    byte[] buffer = new byte[1024];                    int Len;                   while ((Len=in.read (buffer))!=-1) {out.write (Buffer,0,len); } return DefineClass (Classname,out.tobytearray (), 0,out.size ());                }catch (Exception e) {e.printstacktrace ();                    }finally {classfile.delete ();                        if (null!=in) {try{in.close ();                        }catch (Exception e) {e.printstacktrace (); }} if (Null!=out) {try{out.close                        ();                        }catch (Exception e) {e.printstacktrace ();    }}}}} return null; }}
Summarize

Above I modeled the JDK with its own API to implement the proxy, so that once written to the principle of the implementation of the proxy deepened a lot. Proxy as an important model has been used in a lot of the current popular framework, understand the principle of more confidence to learn the framework and the implementation of the framework of the idea .

Advantages: 1. Clear responsibilities, real role focus on the realization of business logic, agent role to complete specific transactions, code structure concise and clear; 2. Can be extended

Add

The above studies the implementation of the JDK dynamic agent, first defines the interface, and then implements the interface with a class, the implementation class is to be the specific object of the agent;

The Cglib library also implements the proxy pattern, unlike the JDK, where cglib does not need to define interfaces, but instead implements proxy patterns by generating subclasses of the proxy class. This makes the use of proxy mode easier. Generic types can be used as proxy types.

The approximate implementation is as follows (the principle is similar to the JDK implementation, except that Cglib uses class inheritance implementations):

 /** * Demo Cglib proxy Way */public class Cgagent implements Methodinterceptor {public Object Getinst        ance (Class clazz) throws exception{enhancer enhancer = new enhancer ();        Enhancer.setsuperclass (Clazz);        Enhancer.setcallback (this);    return Enhancer.create ();        } public Object intercept (object O, Method method, object[] objects, Methodproxy methodproxy) throws Throwable {        SYSTEM.OUT.PRINTLN ("Agent started ....");        Methodproxy.invokesuper (o,objects);        System.out.println ("The agent has ended ....");    return null; }}

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.