A detailed explanation of the implementation mechanism of Java dynamic proxy _java

Source: Internet
Author: User
Tags inheritance reflection static class throwable

I. Overview
A proxy is a design pattern designed to provide a proxy for other objects to control access to an object, which is responsible for preprocessing messages for the delegate class, filtering messages and forwarding messages, and subsequent processing after the message is executed by the delegate class. To keep the behavior consistent, proxy classes and delegate classes typically implement the same interface.

According to the creation period of the agent, the proxy class can be divided into two types:

static agents: The programmer creates a proxy class or a specific tool to automatically generate the source code and then compile it, which means that the. class file of the proxy class already exists before the program is run.
Dynamic Proxy: Create a build dynamically using the reflection mechanism when the program is running.
The following is a brief introduction to the static proxy before implementing the dynamic proxy implementation mechanism.

Second, static agent
As stated above, the proxy class and the delegate class are generally implemented with the same interface, which is defined here first:

Public interface Service
{public  
  void Add ();
}

A delegate class is an implementation of an interface, defined as follows:

public class Serviceimpl implements Service
{public
  void Add ()
  {
    System.out.println add user! ");
    
  }
}

If we want to add some log operations to the delegate class, the proxy class can be defined as follows:

public class Serviceproxy implements service
{
  Private service service;
  Public serviceproxy (Service service)
  {
    super ();
    This.service = service;
  }
  public void Add ()
  {
    System.out.println ("start of Service");
    Service.add ();
    System.out.println ("End of Service");
  }


To write a test class:

public class Testmain
{public
  static void Main (string[] args)
  {
    Service serviceimpl=new Serviceimpl ();
    Service proxy=new serviceproxy (Serviceimpl);
    Proxy.add ();
  }

Run the test program, the result of the following figure:

As you can see from the above code, static proxy classes can only serve specific interfaces, and if you want to serve multiple types of objects, you should proxy each object. We will think about whether we can do all the agent functions through a proxy class, and then introduce the concept of dynamic agent.

Third, dynamic agent
Java dynamic Proxy mainly involves two classes, proxies and Invocationhandler.

  Proxy: provides a set of static methods for dynamically generating proxy classes and their objects for a set of interfaces.

Method 1: This method is used to get the call processor
static Invocationhandler Getinvocationhandler (object proxy)

/method associated with the specified proxy object 2: This method is used to get the class object
static Class Getproxyclass (ClassLoader loader, class[] interfaces) associated with the dynamic proxy class of the specified class loader and a set of interfaces

/methods 3: This method is used to determine whether a specified class object is a dynamic proxy class
static Boolean Isproxyclass (class CL)

//Method 4: This method is used to generate a dynamic proxy class instance for a specified class loader, a set of interfaces, and a calling processor
static Object newproxyinstance (ClassLoader loader, class[] Interfaces,invocationhandler h)


Invocationhandler: It is the calling processor interface, which customizes a Invok method for centralizing the method invocation on the dynamic proxy class object, typically implementing proxy access to the delegate class in the method

This method is responsible for centralizing all method calls on the dynamic proxy class. The first parameter is both a proxy class instance and the second parameter is the invoked method object
//The third method is the invocation parameter. The calling processor is preprocessed based on these three parameters or assigned to a delegate class instance to emit execution
object Invoke (Object proxy, Method method, object[] args)

The implementation of Java dynamic Proxy, the following four steps are specific:

1, through the implementation of the Invocationhandler interface to create their own call processor
2. Create a dynamic proxy class by specifying the ClassLoader object and a set of interface for the proxy class
3, through the reflection mechanism to obtain the dynamic proxy class constructor, the only parameter type is to call the Processor class interface type
4. Create a dynamic proxy class instance by using the constructor function to call the processor object as a parameter to be passed in

The following four steps are implemented to implement your own example of a dynamic proxy:

Interface and interface implementation class (that is, the delegate class) with the above static proxy code, here we implement the Invocationhandler interface to create their own call processor

public class Servicehandle implements Invocationhandler
{
  private Object s;
  
  Public Servicehandle (Object s)
  {
    THIS.S = s;
  }
  public object invoke (object proxy, Method method, object[] args)
      throws Throwable
  {
    System.out.println (" Service start ");
    Invoke represents the underlying method object
    Result=method.invoke (S, args)
    that is represented on the specified object with the specified parameter by invoking the expression of the methods. System.out.println ("End of Service");
    return result;
  }


To write a test class:

public class Testmain
{public
  static void Main (string[] args)
  {
    Service service=new serviceimpl ();
    Invocationhandler handler=new servicehandle (service);
    Service s= (Service) proxy.newproxyinstance (Service.getclass (). getClassLoader (), Service.getclass (). Getinterfaces ( ), handler);
    S.add ();
  }

Run the test program, the result is the same as static agent. We can see that the above code does not have the steps 2 and 3 we said earlier, because the ProX static method Newproxyinstance has encapsulated these two steps for us. The specific internal implementation is as follows:

Class object classes
clazz = Proxy.getproxyclass (ClassLoader, new class[] {Interface) dynamically creating proxy classes for a set of interfaces including the Interface interface via proxy . class, ...});

Gets the constructor object
constructor constructor = Clazz.getconstructor (new class[] {Invocationhandler.class}) from the generated class object by reflection; c14/>//creates a dynamic proxy class instance through a constructor object
Interface proxy = (Interface) constructor.newinstance (new object[] {handler});

The internal implementation of the Newproxyinstance function is:

public static Object newproxyinstance (ClassLoader loader, class<?>[] Interfaces,invocationhandler h) throws
      illegalargumentexception {//check h is not null, otherwise throw abnormal objects.requirenonnull (h);
      
      Get the proxy class type object related to the development class loader and a set of interfaces final class<?>[] Intfs = Interfaces.clone ();  
      Check that the interface class object is visible to the class loader and is exactly the same as the interface class object that the class loader can recognize: final SecurityManager sm = System.getsecuritymanager ();
      if (SM!= null) {checkproxyaccess (Reflection.getcallerclass (), loader, intfs);
      //Get the proxy class type object associated with the development class loader and a set of interfaces class<?> cl = GETPROXYCLASS0 (loader, intfs);
        try {if (SM!= null) {checknewproxypermission (Reflection.getcallerclass (), CL);
        ///Get constructor object through reflection and generate proxy class instance 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);
      The catch (Nosuchmethodexception e) {throw new Internalerror (E.tostring (), E);
 }  }

Iv. simulate the implementation of proxy class

According to the principle above, we can simulate the proxy class ourselves:

public class Proxy {public static Object Newproxyinstance (class Inface,invocationhandle h) throws Exception {St
    Ring rt= "\ r \ n";
    String methodstr= "";
    Method[] Methods=inface.getmethods ();
          For [method M:methods] {methodstr+= "@Override" +rt+ "public void" +m.getname () + "()" +rt+ "{" + RT + "Try {" +rt+ "method md=" +inface.getname () + ". Class.getmethod (\" "+m.getname () +" \ ");" +rt+ "H.invoke (THIS,MD);" +rt+ "} catch (Exception e) {e.printstacktrace ();}"
    +rt+ "}"; String src= "package test;" +rt+ "Import Java.lang.reflect.Method;" +rt+ ' public class SERVICEIMPL2 implements ' +inface.getname () + rt+ ' {' +rt+ ' public ServiceImpl2 ( Invocationhandle h) "+rt+" {"+rt+" this.h = h; " +rt+ "}" +rt+ "test. Invocationhandle h; "
    +rt+ methodstr+ "}";
    String filename= "D:/src/test/serviceimpl2.java";
Compile    Compile (src, fileName);
    
    Load into memory and create instance Object m = loadmemory (h);
  return m;
    The private static void compile (string src, String fileName) throws IOException {file F=new file (filename);
    FileWriter filewriter=new FileWriter (f);
    Filewriter.write (SRC);
    Filewriter.flush ();
    Filewriter.close ();
    Gets the Java compiler Javacompiler Compiler=toolprovider.getsystemjavacompiler () provided by this platform;
    Gets a new instance of the standard File Manager implementation Standardjavafilemanager Filemanager=compiler.getstandardfilemanager (null,null, NULL);
    Gets the file object that represents the given file iterable units=filemanager.getjavafileobjects (fileName);
    Creates the future Compilationtask t=compiler.gettask (null, filemanager, NULL, NULL, NULL, units) of the compilation task using the given components and parameters;  
    Perform this compilation task T.call ();
  Filemanager.close ();
      private static Object Loadmemory (Invocationhandle h) throws Malformedurlexception, ClassNotFoundException, Nosuchmethodexception, Instantiationexception, IllegalaccessexCeption, invocationtargetexception {url[] urls=new url[] {new URL ("file:/" + "d:/src/")};
    Load classes and Resources URLClassLoader ul=new URLClassLoader (URLs) from the path d:/src/; Class c=ul.loadclass ("Test.
    ServiceImpl2 ");  
    Returns the specified public constructor method for the class represented by the class object.
    Constructor Ctr=c.getconstructor (Invocationhandle.class);
    Creates a new instance of the Declaration class for the constructor using this constructor object Ctr The constructed method represented by the method, and initializes the instance object m = Ctr.newinstance (h) with the specified initialization parameter;
  return m;
 }
}

V. Summary
1, the so-called dynamic agent is such a class, it is generated at runtime class, in the generation of it you have to provide a set of interface to it, and then change class to declare that it achieved these interface, but in fact it will not do for you substantive work, Instead, this handler takes over the actual work based on the parameter handler (that is, the implementation class of the Invocationhandler interface) that you provide when generating the instance.

2, proxy design so that it can only support the interface agent, the Java inheritance mechanism is doomed to dynamic proxy class can not implement the dynamic proxy, because many inheritance in the Java in nature is not feasible.

The above is the entire content of this article, I hope to help you learn.

Related Article

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.