当前位置:网站首页>And let's play dynamic proxy (extreme depth version)

And let's play dynamic proxy (extreme depth version)

2022-07-05 07:16:00 I am the king of X

Disgusting things take time to make them more disgusting 🧎‍*️ ----xmonster

The opening

You can see it. 《 Zen of design pattern 》( The first 2 edition ) Understanding of agency mode in , He used “ Play strange games ” Example , I think it's very vivid , Understand very thoroughly ! If you are not very clear about the agency mode , Then dynamic proxy is naturally more difficult for you to understand , Don't do useless work , First, fill the foundation ( Don't forget to make it up and come back ); If you already know , Then go on !
Let's have a picture , It doesn't make any sense , Just to wake up , This is the flow chart of the book above
This blog post is long , Please be patient after reading

 Insert picture description here
🧡🧡🧡🧡🧡
 Insert picture description here

Go through Baidu Encyclopedia

Dynamic proxy class

Java The dynamic proxy class is located in Java.lang.reflect It's a bag , Here and Java The reflection of is closely related , If you don't understand Java Reflection of , It is difficult to understand dynamic proxy , Here is an article about Java Summary of the basic understanding of reflection , Mainly refer to Baidu Encyclopedia : Big talk Java The reflex mechanism

Generally, the following two categories are involved :

One 、Interface InvocationHandler: There is only one method defined in this interface Object:invoke(Object obj,Method method,Object[] args). In actual use , The first parameter obj Generally speaking, it means proxy class ,method yes The method of being represented ,args For the parameter array of this method . This abstract method is implemented dynamically in the proxy class .

Two 、Proxy: This class is called dynamic proxy class, which mainly includes the following contents :
Protected Proxy(InvocationHandler h): Constructors , Estimated for internal h assignment .
Static Class getProxyClass (ClassLoader loader,Class[] interfaces): Get a proxy class , among loader It's a class loader ,interfaces Is an array of all interfaces owned by a real class .( Create a proxy for an interface )
Focus on the following methods :

Static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h): return An instance of the proxy class , The returned proxy class can be used as the proxied class ( You can use the proxied class in Subject Methods declared in the interface ).
So-called Dynamic Proxy It's like this class: It's generated at run time class, When generating it You must provide a set interface Give it , And then the class To claim that it has achieved these interface. Of course you can put the class As an example of these interface Use any one of them . Of course! , This Dynamic Proxy It's really just a Proxy, It doesn't do substantive work for you , When generating its instance You have to provide a handler, It takes over the actual work .

Agency mechanism and characteristics ( Use steps )

By implementing InvocationHandler Interface to create its own call handler ;
By providing Proxy class Appoint ClassLoader object and A group of interface To create a dynamic proxy class ;
Get the constructor of the dynamic proxy class through the reflection mechanism , Its only parameter type is the call handler interface type ;
Creating a dynamic proxy class instance through a constructor , The call handler object is passed in as a parameter during construction .

It doesn't understand , No problem , Now take your time
The following code completes the corresponding dynamic proxy implementation in this order

Tool class code of dynamic proxy

The following code comments are my personal understanding , Somewhat chaotic , But it's very nice, You can also skip directly ~

package com.xmonster.demo01;

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

// Later, we will use this class to automatically generate proxy classes !
public class ProxyInvocationHandler implements InvocationHandler {
    

// Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
// new Class<?>[] { Foo.class },
// handler);

//  The interface being proxied 
// 1、 Proxy an interface   Who is this interface , Is the real object ; The real object will implement that interface , We'll finish acting for it 
    private Object target;
    public void setTarget(Object target) {
    
        this.target = target;
    }

    // Generate the proxy class 
    public Object getProxy(){
    
// getClassLoader() Class loader : It is responsible for loading bytecode files into memory , establish Class object 
// target.getClass().getClassLoader()  adopt target From the example Loader() Information 
// target.getClass().getInterfaces()  Get the corresponding interfaces Information ( Reflection )
// System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// target.getClass().getClassLoader()
        /* target.getClass() Get its class object  * getClassLoader(): Every Class Objects have a method , You can get it ClassLoader * target.getClass().getClassLoader(): Get the class and get the class loader of this class  * * * * */


      return  Proxy.newProxyInstance(target.getClass().getClassLoader(),
              target.getClass().getInterfaces(),
              this);
// newProxyInstance: Returns an instance of the proxy class for the specified interface , This interface dispatches method calls to the specified call handler .
// loader -  Class loader to define the proxy class 
//interfaces -  List of interfaces implemented by proxy class 
//h -  Call handler for scheduling method calls 

    }
    // Handling agent instances , And return the result 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
        // The proxy is an interface 
        // The essence of dynamic proxy , Is to use reflection mechanism to achieve 
        setHost();
        Object invoke = method.invoke(target, args);
        return invoke;
    }
}

This code is believed to be familiar to experienced old dogs , This code is written by watching the video of crazy God , So his example is also used , Examples of landlords and intermediaries , Now let's explore the meaning and use of the above code
Let's start with a test class

package com.xmonster.demo01;

public class Client {
    
    public static void main(String[] args) {
    
//  Real object 
        UserService userService = new UserServiceImpl();
//  Proxy object 
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
//  Generate proxy roles 
        pih.setTarget(userService);   // Set the object to be represented 
//  Dynamic generation 、 Get the proxy class , Get proxy class object 
//  Notice the cast here 
        UserService proxy =(UserService)  pih.getProxy();
// Object proxy = pih.getProxy();
//  Just call the method of the responding agent 
        proxy.query();
    }
}

analysis

Back to what we said above , Both the proxy class and the proxied class implement one “ Interface ”, Only the proxy class passes a parameter ( Pass the proxied class ), Then help the proxy class do things , So the point is “ Interface ”
( Proxies and actual objects generally have the same interface )

That's why

UserService proxy =(UserService)  pih.getProxy();

Here is the reason for the strong turn

It's not like adapters and decorators , Because agents are generally Do not change the interface

Realization way

Implementation methods generally include 2 Kind of , One is Java SDK, One is cglib
Here's about newProxyInstance、InvocationHandler The examples and parameters are understood in this blog :
And play the little chestnut of dynamic proxy
Because we also need to combine this example to play , So let's first look at the above example , Contrast understanding
take SimpleInvocationHandler The main function of is implemented in another way :

Class<?> proxyClass = Proxy.getProxyClass(IService.class.getClassLoader(),
              new Class<?>[] {
    IService.class});

      Constructor<?> ctor = proxyClass.getConstructor(new Class<?>[] {
    InvocationHandler.class});
      InvocationHandler handle = new SimpleInvocationHandler(realService);

      IService proxyService = (IService) ctor.newInstance(handle);
      proxyService.sayHello();

Understand the steps :

  1. adopt Proxy.getProxyClass That created the proxy class “ Definition ”, Class definitions will be cached ;
  2. Get the construction method of the class , One of the construction methods is InvocationHandler Parameters of type
  3. establish InvocationHandler object , The proxy object is created

Proxy.getProxyClass

The source of this method :

    public static Class<?> getProxyClass(ClassLoader loader,
                                         Class<?>... interfaces)
        throws IllegalArgumentException
    {
    
        Class<?> caller = System.getSecurityManager() == null
                              ? null
                              : Reflection.getCallerClass();

        return getProxyConstructor(caller, loader, interfaces)
            .getDeclaringClass();
    }

You can see that this method requires two parameters , One is ClassLoader, The other is the interface array

Given the class loader and interface array of proxy classes java.lang.Class object . The proxy class will be defined by the specified class loader , And will implement all provided interfaces . If any given interface is not public , Then the proxy class will be non-public . If the class loader has defined a proxy class with the same interface substitution , Then the existing proxy class will be returned ; otherwise , The proxy classes of these interfaces will be dynamically generated and defined by the class loader .
This method will dynamically generate a class , The class name is $Proxy start , Then it will be followed by some numbers

Parameters
loader - Class loader to define the proxy class
interfaces - List of interfaces of proxy classes to be implemented
result
Define and implement the proxy class of the specified interface in the specified class loader

Given by this method Class loader and Interface array proxy class java.lang.Class object . The proxy class will be defined by the specified class loader , And will implement all provided interfaces . If any given interface is not public , Then the proxy class will be non-public . If the class loader has defined a proxy class with the same interface substitution , Then the existing proxy class will be returned ; otherwise , The proxy classes of these interfaces will be dynamically generated and defined by the class loader .

$Proxy0

Here's the analysis $Proxy0 The source code will be particularly clear ( The code is long , It's not released here , You can baidu , They all look the same , It mainly depends on its construction method and structure )

$Proxy0 The parent class is Proxy, And it has a construction method , Accept one InvocationHandler Parameters of type , Save as instance variables h,h Defined in the parent class Proxy Kind of , It implements the interface IService, For each method , Will be called InvocationHandler Of invoke Method , about Object Many methods in , Also transferred to InvocationHandler
The class definition itself has nothing to do with the object being represented , And InvocationHandler It doesn't matter whether it's a concrete implementation of , It is mainly related to interface array , Given this interface array , It will dynamically create the implementation code of each interface , Implementation is to forward to InvocationHandler, With the proxied object and its call by InvocationHandler Implementation management

The next step is to get the constructor , Create proxy object !

getConstructor

@CallerSensitive
public Constructor<T> getConstructor(Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException
{
    
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
    
        checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
    }
    return getReflectionFactory().copyConstructor(
        getConstructor0(parameterTypes, Member.PUBLIC));
}
  • getConstructor Method returns a Constructor object , This object reflects Constructor The specified public class function of the class represented by the object . parameterTypes Parameters are an array of class objects that identify the formal parameter type of the constructor in the order of declaration . If such an object represents an inner class declared in a non static context , Then the formal parameter type will explicitly surround the instance as the first parameter .

newInstance

public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException
  • Use this Constructor Object represents the constructor , Creates and initializes a new instance of the constructor's declaration class with the specified initialization parameters . Individual parameters are automatically unpacked to match the original formal parameters , Both the original reference parameters and the reference parameters need to be converted into method calls .
  • If the constructor completes normally , Then return the newly created and initialized instance .
  • Parameters initargs - An array of objects to be passed as arguments to constructor calls ; The value of the original type is wrapped in a wrapper object of the appropriate type ( for example float Medium float )

result
A new object created by calling the constructor represented by this object

In this way, the whole process is basically over

原网站

版权声明
本文为[I am the king of X]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202140558358179.html