This is the 9th day of my participation in the August More Text Challenge

Agent mode has been enabled after Builder mode. 😁 Java Design Patterns series – Proxy patterns. You and I insist together, let us refueling together, will not learn a study together, we will review it. 😁 like a sentence: “eight hours for life, eight hours for survival”

Hello, if you like, please stick to it!! I hope that when I meet you, you will have achieved something. 😁

'

An old picture, trance thought of old people

Design Mode series:

  • Java Design pattern – singleton pattern
  • Java Design Pattern – Factory Pattern (1) Simple Factory pattern
  • Java Design Pattern – Factory Pattern (2) Factory method pattern
  • Java Design Pattern – Factory Pattern (3) Abstract Factory pattern
  • Java Design pattern – Builder pattern
  • Java Design pattern – Proxy pattern
  • Java Design pattern – Adapter pattern
  • Java Design pattern – Decorator pattern
  • Java Design pattern – Bridge pattern
  • Java Design pattern – Appearance pattern
  • Java Design pattern – Composite pattern
  • Java Design pattern – Share meta pattern
  • Java Design Pattern – Template method pattern
  • Java Design pattern – Policy pattern
  • Java Design pattern – Chain of Responsibility pattern
  • Java Design Pattern – The Mediator pattern
  • Java Design Pattern – Observer Pattern (publish/subscribe pattern)
  • Continuously updated…

One, foreword

In some cases, a client cannot or does not want to directly access another object, and a mediation is needed to help complete a task. This mediation is a proxy object. For example, you don’t have to go to the railway station to buy train tickets. You can buy them on 12306.cn or at train ticket sales agencies. If look for girlfriend again, look for nurse, look for a job to wait to be able to complete through looking for intermediary.

There are also many examples of proxy patterns in software design, such as when the remote object to be accessed is large (such as a video or a large image) and takes a long time to download. There are also security reasons to shield clients from direct access to real objects, such as the internal database of a unit.

1) Overview:

Provide a proxy for other objects to control access to that object. In some cases, an object is inappropriate or cannot directly reference another object, and a proxy object can act as an intermediary between the client and the target object.

Java proxies can be divided into static proxies and dynamic proxies according to the generation time of proxy classes. Static proxy proxy classes are generated at compile time, whereas dynamic proxy proxy classes are generated dynamically at Java runtime. Dynamic proxies include JDK proxies and CGLib proxies.

2) Structure:

The Proxy mode is divided into three roles:

  • Abstract roles: Business methods that declare real topics and proxy object implementations through interfaces or abstract classes.
  • Real role: Implements the abstract role and defines the business logic to be implemented by the real role for the proxy role to invoke.
  • Proxy class: Implements abstract roles, is the Proxy of real roles, through the business logic methods of real roles to implement abstract methods, and can attach its own operations.

3) Static and dynamic proxies

According to the creation time of the agent, the agent mode can be divided into static agent and dynamic agent.

  • Static: a programmer creates a proxy class or a specific tool automatically generates source code and compiles it. The.class file of the proxy class exists before the program runs.
  • Dynamic: dynamically created using reflection while the program is running

Static proxy

Let’s take the experience of a client who wanted to buy a second-hand house as an example. In the past, when there was no intermediary agency, he would directly go to the landlord to buy the house. Now the landlord is busy with other things and has no time to do this. Now all we have to do is go to a real estate agent and get it done.

2.1. Small cases

First look at the graph:

2.2, code,

SellHouse (Abstract roles: business methods that declare real topics and proxy object implementations through interfaces or abstract classes.)

public interface SellHouse {
    /** interface method */
    void sell(a);
}
Copy the code

Landlord (implements the abstract role and defines the business logic to be implemented by the real role for the proxy role to call.)

public class Landlord implements SellHouse{
    @Override
    public void sell(a) {
        System.out.println("Landlord for sale!!"); }}Copy the code

ProxyPoint (Proxy role: implements abstract role, is the proxy of the real role, implements abstract method through the business logic method of the real role, and can attach its own operations)

The additional operation here is to receive poundage 😁

public class ProxyPoint implements SellHouse{

    private Landlord landlord=new Landlord();

    @Override
    public void sell(a) {
        System.out.println("Real estate agents charge intermediary fees to help landlords sell houses,!!"); landlord.sell(); }}Copy the code

Testing:

public class Client {
    public static void main(String[] args) {
        ProxyPoint point = new ProxyPoint();
        point.sell();
        /** * Real estate agents charge intermediary fees to help landlords sell houses,!! * Landlord for sale!! * /}}Copy the code

It can be seen from the above test code that we directly access the ProxyPoint class object, that is, ProxyPoint acts as the intermediary between accessing the object and the target object. The Sell method has also been enhanced (agents charge some fees for their services).

You can now see that the proxy pattern can add and enhance functionality by extending the proxy class without modifying the proxied object. It is important to note that the proxied and proxied classes should implement an interface or inherit from a class in common.

Dynamic proxy

The example is the one above, but I won’t give you the picture

Let’s use dynamic proxies to implement the above example, starting with the dynamic proxies provided by the JDK. Java provides a dynamic Proxy class, Proxy, which is not the class of the Proxy object mentioned above, but provides a static method (newProxyInstance method) to create the Proxy object to get the Proxy object.

1, code,

SellHouse (Abstract roles: business methods that declare real topics and proxy object implementations through interfaces or abstract classes.)

public interface SellHouse {
    /** interface method */
    void sell(a);
}
Copy the code

Landlord (implements the abstract role and defines the business logic to be implemented by the real role for the proxy role to call.)

public class Landlord implements SellHouse {
    @Override
    public void sell(a) {
        System.out.println("Landlord for sale!!"); }}Copy the code

ProxyFactory (is it a proxy class?)

public class ProxyFactory {

    private Landlord landlord = new Landlord();

    public SellHouse getProxyObject(a) {
        NewProxyInstance () : /** * the newProxyInstance() method is used to obtain a Proxy object. InvocationHandler h: the call handler for the proxy object */
        SellHouse sellHouse=(SellHouse) Proxy.newProxyInstance(
                landlord.getClass().getClassLoader(),
                landlord.getClass().getInterfaces(),
                new InvocationHandler() {
                    Method: the method instance corresponding to the interface method called on the proxy object args: the actual parameter passed when the proxy object calls the interface method */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("Real estate agents charge fees.");
                        // Execute the real object and return it if it has a return value
                        Object o = method.invoke(landlord, args);
                        returno; }});returnsellHouse; }}Copy the code

I just learned a trick yesterday

Let’s go back to the question above.

We’re using the JDK dynamic proxy, ProxyFactory which is a proxy class, right?

Answer: Not really. ProxyFactory is not a proxy class in the proxy mode. Proxy classes are dynamically generated in-memory classes during program execution.

We can print it in the test code.

System.out.println(proxyFactory.getClass());
System.out.println(house.getClass());
Com.crush. Jdk_proxy.proxyfactory * class com.sun.proxy.$Proxy0 */
Copy the code

We can see that the real dynamically generated proxy is actually class com.sun.proxy.$Proxy0. That’s what’s going on in the program.

Next I use what I learned yesterday, let everyone have a look, ~~ technique unfamiliar forgive me ha. ~ ~ 😂

2. Dynamic proxy analysis

Take your time 😁

Arthas Is an open source Java diagnostic tool that we can download from Alibaba.

Arthas official documentation (this is used in the JDK8 environment, using a tools.jar tool in JDK8)

Note :(if the other version seems to be unable to start, I have 8 and 11 in the computer, 8 did not configure the environment variable, and then, there are always error, I will change idea to jdk8 version, recompile, and then directly CMD in jdk8 environment start and then it is still ok).

Note: FOR monitoring purposes, I add a while(ture){} to the test method.

Look at the structure of the proxy class:

$Proxy0 = com.sun.proxy.$Proxy0 = com.sun.proxy.$Proxy0 = com.sun

[arthas@3012]$ jad com.sun.proxy.$Proxy0
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@b4aac2
  +-sun.misc.Launcher$ExtClassLoader@c21c27

Location:

/* * Decompiled with CFR. * * Could not load the following classes: * com.crush.jdk_proxy.SellHouse */
package com.sun.proxy;

import com.crush.jdk_proxy.SellHouse;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
extends Proxy
implements SellHouse {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString".new Class[0]);
            m3 = Class.forName("com.crush.jdk_proxy.SellHouse").getMethod("sell".new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode".new Class[0]);
            return;
        }
        catch (NoSuchMethodException noSuchMethodException) {
            throw new NoSuchMethodError(noSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException classNotFoundException) {
            throw newNoClassDefFoundError(classNotFoundException.getMessage()); }}public final boolean equals(Object object) {
        try {
            return (Boolean)this.h.invoke(this, m1, new Object[]{object});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw newUndeclaredThrowableException(throwable); }}public final String toString(a) {
        try {
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw newUndeclaredThrowableException(throwable); }}public final int hashCode(a) {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw newUndeclaredThrowableException(throwable); }}public final void sell(a) {
        try {
            this.h.invoke(this, m3, null);
            return;
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw newUndeclaredThrowableException(throwable); }}}Copy the code

After removing useless information:

3. Analyze the process

Proxy classes that are dynamically generated during program execution

$Proxy0 extends Proxy to implement SellHouse
public final class $Proxy0 extends Proxy implements SellHouse {
    private static Method m3;

    // The parent constructor used here has the following constructor
    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    static {
        m3 = Class.forName("com.crush.jdk_proxy.SellHouse").getMethod("sell".new Class[0]);
        return;
    }

    
    public final void sell(a) {
     	// You can see that this is the actual method being executed where h is the InvocationHandler member of the parent class
        //invoke: handles a method call on a proxy instance and returns a result. This method is called on the invocation handler when it is invoked on the proxy instance associated with it.
        this.h.invoke(this, m3, null);
        return; }}Copy the code

Let’s take a look at the key things about Proxy.

public class Proxy implements java.io.Serializable {

    protected InvocationHandler h;

    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h; }}Copy the code

Now let’s take a look at our proxy generation class ProxyFactory

public class ProxyFactory {

    private Landlord landlord = new Landlord();

    public SellHouse getProxyObject(a) {
        SellHouse sellHouse=(SellHouse) Proxy.newProxyInstance(
                landlord.getClass().getClassLoader(),
                landlord.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("Real estate agents charge fees.");
                        Object o = method.invoke(landlord, args);
                        returno; }});returnsellHouse; }}// Test the code
public class Client {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = newProxyFactory(); SellHouse house = proxyFactory.getProxyObject(); house.sell(); }}Copy the code

The execution process is as follows:

$Proxy0 = $Proxy0; $Proxy0 = $Proxy0; $Proxy0 = $Proxy0; Invoke ($Proxy0) invoke ($Proxy0) invoke ($Proxy0) invoke ($Proxy0) invoke ($Proxy0) invoke ($Proxy0) Invoke ($Proxy0) Invoke ($Proxy0Copy the code

The dynamic proxy of GCLB is not analyzed further, some uses are slightly different, but can be understood. 😁

4 Advantages and disadvantages:

The main advantages of the proxy model are:

  • Proxy mode plays an intermediary role and protects the target object between the client and the target object.
  • Proxy objects extend the functionality of target objects;
  • The proxy mode can separate the client from the target object, reduce the coupling degree of the system to a certain extent, and increase the scalability of the program

Its main disadvantages are:

  • The proxy pattern increases the number of classes in the system design
  • Adding a proxy object between the client and the target object slows down request processing.
  • Increased the complexity of the system;

4. Talk to yourself

You roll me roll, everyone roll, when this road is the end ah. 😇 (or directly to heaven)

Sometimes I want to stop and have a rest. It’s hard to stick to one thing all the time. 😁

Hi, if you happen to read this article and think it’s good for you, give it a thumbs up and let me feel the joy of sharing, Crab. 🤗

If there is something wrong, please don’t add to it!!

Similarly, if there is any doubt, please leave a message or private message, we will reply to you in the first time.

Ongoing update