From the agency model caused by the sale of houses by Zhang San, a fanatic outside the law

The official account of WeChat: Rhubarb running
Follow me to learn more interesting interview related questions.

Write before

When it comes to proxy mode, the most common use scenario is the use of in AOP. Before discussing the implementation of AOP, let's talk about what proxy mode.

There are two forms of dynamic agent, static agent and dynamic agent. You don't need to pay attention to their concepts first. After understanding this article, you will find that there is little difference between the two.

Static proxy

Use a simple example to analyze what is static agent. Take buying a house and selling a house as an example to talk about the role of agent mode and why it is used so frequently.

Subject interface: used to abstract the interviewee (such as selling a house)

SubjectImpl: the specific implementation of the interviewee (Zhang San wants to sell a house)

SubjectProxy: the proxy implementation class of the interviewee. This class needs a specific instance of the Subject interface. (for example, a real estate agent can only act with the authorization of Zhang San)

Client: the abstraction of the visitor. (for example, if Li Si wants to buy a house, he is a customer)

The agent class itself works for the interviewee. Li Si wants to buy a house and puts forward many requirements, such as facing south and school district room; The real estate agent (SubjectProxy) saw that the house of Zhang San's family just met Li Si's expectations and introduced Zhang San's house to Li Si; Equivalent to being an intermediary. One might say, is it similar to an introduction? Do you have to let the intermediary come? If it's just a simple introduction, you really don't need an intermediary, but the intermediary can help run the loan, help grasp the contract, etc.

In this way, Zhang San only needs to authorize the intermediary to complete the transaction with less worry while doing other things.

The above figure naturally becomes the following pattern

Proxy abstract interface - house

public interface House {
    /**
     * Sell the house
     */
    void sell();
}

The class visited -- Zhang San's house

public class HouseForZhangsan implements House {


    @Override
    public void sell() {
        System.out.println("zhangsan sell house............");
    }
}

Agent - real estate agent

public class HouseProxy implements House {

    private House house;

    // Through the construction method, we can act for different people each time
    public HouseProxy (House house) {
        this.house = house;
    }
    @Override
    public void sell() {
        house = new HouseForZhangsan();
        house.sell();
    }
}

Test class - trading place

public class Test {

    public static void main(String[] args) {
        // Construct specific sellers
        House house = new HouseForZhangsan();
        // Give Zhang San to the intermediary agent
        House houseForPerson = new HouseProxy(house);
        houseForPerson.sell();
    }
}

Or return to the Spring AOP mode, where SubjectProxy is like the intermediary of SubjectImpl, and SubjectImpl itself is the object (target object) where the JoinPoint in the system is located. It is logical to create a proxy object for the target object to complete the logic of the aspect.

But let's think about it. There are not only houses to sell in the market. Zhang San's family has a spare car and wants to sell it. Can you still find a real estate agent?

Definitely not.

As a result, intermediaries specialized in car trading have emerged, such as melon seeds used cars (it is said that there is no middleman to earn the price difference, hahaha), used car homes and so on.

For another example, if Zhang San suddenly finds that his mobile phone has been used for a long time and wants to sell his second-hand mobile phone and a new iPhone, there are all kinds of second-hand mobile phone platforms (in fact, it is also an intermediary in essence)

......

......

Wait, someone might wonder, can we set up an intermediary and sell everything? So a more comprehensive second-hand platform came into being.

In this way, you can flexibly proxy various commodities (the proxy object), which achieves the effect of a dynamic intermediary.

Yes, yes, the dynamic agent has been introduced.

I'm kidding. Let's continue to talk about how Spring AOP makes use of dynamic proxies.

Dynamic agent

You can specify the interface to dynamically generate proxy objects during runtime. (in other words: no matter what you want to sell, you can find a corresponding intermediary when you come)

So how to dynamically generate proxy classes?

Two tools are needed, one is Java lang.reflect. Proxy class and Java lang.reflect. Invocationhandler, the key to the problem is how to generate an intermediary to satisfy customers in real time.

This is to dynamically generate proxy classes with InvocationHandler, or take the above mediation as an example. For the moment, the proxy class to be generated is called target

How to dynamically generate different types of mediations?

In the first step, you must know what type of client agent you are acting for at this time, but you can't write it too dead. Let's declare a proxy object in the generated proxy class first.

Step 2: pass in the proxy object in some way

Step 3: bind the proxy object to the mediation.

/**
 * Target of the agent
 */
public Object target;

/**
 * Bind the delegate object and generate the proxy class
 * @param target
 * @return
 */
public Object bind(Object target) {
    this.target = target;
    //Bind all interfaces implemented by this class to obtain the proxy class
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                                  target.getClass().getInterfaces(), this);
}   

After the deployment of the above steps, you will understand who the intermediary will work for and what the intermediary will do, and associate the intermediary with the customer.

The last thing is to really work for customers.

public class SellInvocationHandler implements InvocationHandler {

    /**
     * Proxy target
     */
    public Object target;

    /**
     * Bind the delegate object and generate the proxy class
     * @param target
     * @return
     */
    public Object bind(Object target) {
        this.target = target;
        //Bind all interfaces implemented by this class to obtain the proxy class
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                                      target.getClass().getInterfaces(), this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log.info("Additional logic");
        return method.invoke(target, args);
    }
}

Remember what we said before?

Dynamic agent only solves the problem of flexibly generating different agent classes (in other words, flexibly matching different types of intermediaries)

As for what kind of things to do, and what to do for whom, these two things still have to exist.

Therefore, you still need to declare two classes.

What kind of things do you do

public interface House {
    /**
     * Sell the house
     */
    void sell();
}

Do what for whom

public class HouseForZhangsan implements House {
    @Override
    public void sell() {
        System.out.println("zhangsan sell house............");
    }
}

Then you can trade happily. Every time a new customer comes, you can call different types of intermediaries to serve.

public class DynamicProxyTest {

    public static void main(String[] args) {

        SellInvocationHandler invocationHandler = new SellInvocationHandler();

        // Bind the visited class and agent class to each other (bind the real estate agent to the house seller)
        House house = (House) invocationHandler.bind(new HouseForZhangsan());
        
        // Real implementation
        house.sell();
    }
}

So far, we have completed the real flexible agency work.

Although dynamic agent is good, it can't solve everything. For example, dynamic proxy can only be used for classes that implement the corresponding Interface. If a class does not implement any Interface, it cannot use the dynamic proxy mechanism to generate the corresponding dynamic proxy object for it.

Added by monke on Thu, 10 Feb 2022 23:15:21 +0200