The Spring5 framework provides an in-depth understanding of the use of the beginner’s proxy pattern

“This is the 25th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

About the author

  • The authors introduce

🍓 Blog home Page: author home page 🍓 Introduction: High-quality creator in the JAVA field 🥇, a junior student 🎓, participated in various provincial and national competitions during school, and won a series of honors 🍓, Ali Cloud expert blogger, 51CTO expert blogger, follow me: Pay attention to my learning materials, document download all have, regularly update the article every day, inspirational to do a JAVA senior program ape 👨💻


12. Proxy mode

Experience design patterns for the first time, maybe in the last AOP in some places you may not understand, let’s first explain the idea of AOP design and the underlying principles. Understanding aop later will be relatively easy.

Why learn the proxy pattern, because the underlying mechanism of AOP is dynamic proxies!

Proxy mode:

  • Static agent
  • A dynamic proxy

UML diagrams

12.1 Static Proxy

Static proxy role analysis

ISubject(Abstract Role) : Implemented using interfaces and abstract classes.

RealSubject: The role being proxied.

Proxy: Proxy for a real role. After proxy for a real role, there are ancillary operations.

Client: Uses the agent to select its own requirements.

Code implementation

Isubject. Java Abstract role

package com.spring.demo01;

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo01
 * @ClassName: ISubject
 * @Author: Shengrui Zhang *@Date: 2022/2/12 all *@Version: 1.0 * /
// Abstract role: agent
public interface ISubject {
    public void shop(a);
}

Copy the code

Merchant. Java Real role

package com.spring.demo01;

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo01
 * @ClassName: Merchant
 * @Author: Shengrui Zhang *@DateHe: 2022/2/12 *@Version: 1.0 * /
// The merchant's real role
public class Merchant implements ISubject{
    @Override
    public void shop(a) {
        System.out.println("Merchant will send the goods to the agent!!"); }}Copy the code

Proxy. Java Proxy role

package com.spring.demo01;

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo01
 * @ClassName: Proxy
 * @Author: Shengrui Zhang *@Date: 2022/2/12 14:21
 * @Version: 1.0 * /
// Taobao agent agent role
public class Proxy implements ISubject{
    private Merchant merchant;

    public Proxy(Merchant merchant) {
        this.merchant = merchant;
    }

    // The goods after the agent
    @Override
    public void shop(a) {
        merchant.shop();
        buy();
        Insurance_service();
    }

    // The customer buys the goods
    public void buy(a){
        System.out.println("User buys goods");
    }

    // The broker earns the difference
    public void Insurance_service(a){
        System.out.println("The agent provides insurance and other services for the goods."); }}Copy the code

Client. Java Client

package com.spring.demo01;

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo01
 * @ClassName: Client
 * @Author: Shengrui Zhang *@Date: 2022/2/12 * to them@Version: 1.0 * /
// Customer class, general customers will go to the agent to buy goods!
public class Client {
    public static void main(String[] args) {
        // Customers buy goods
        Merchant merchant = new Merchant();
        // The merchant looks for an agent
        Proxy proxy = new Proxy(merchant);

        // The client goes directly to the agentproxy.shop(); }}Copy the code

Analysis of the

In this process, the customer direct contact is intermediary agents, just as in real life, we cannot directly in contact with the merchants, but still able to buy through agent merchant goods, this is the so-called agency model, program is derived from life, so to learn programming, generally more abstract events in the way of looking at life.

summary

  1. In the future, if you write your own interface and you want to get the instantiation object of the interface, the first reaction is to write the factory class
  2. The simple factory differs from the factory method pattern in that the behavior of the generated product is encapsulated in a method, instantiated according to the type of parameter, and there is no abstract interface. In the latter, abstract factories are added to create different products by implementing different factory methods, one method usually corresponds to one product. This method has higher expansibility than the former, and fully conforms to the open-closed principle and dependency inversion principle when demand increases

benefits

  • It can make our real role more pure and not focus on public things.
  • The common business is completed by the agent. The division of business is realized.
  • Common services become more centralized and convenient when they are extended.

disadvantages

  • With more classes and more proxy classes, the amount of work becomes larger and the development efficiency is reduced.

We want the benefits of static proxies without the disadvantages, so here we have dynamic proxies!

12.2 Understanding Static Proxy again

Practice steps:

  1. Create an abstract role, such as zha people usually do user business, abstract up is add delete change check!

    package com.spring.demo02;
    
    / * * *@ProjectName: Spring5study
     * @Package: com.spring.demo02
     * @ClassName: UserService
     * @Author: Shengrui Zhang *@Date: 2022/2/12 14:42
     * @Version: 1.0 * /
    // Abstract roles: add, delete, change and check services
    public interface UserService {
        void add(a);
        void delete(a);
        void update(a);
        void query(a);
    
    }
    Copy the code
  2. We need a real object to do this

    package com.spring.demo02;
    
    / * * *@ProjectName: Spring5study
     * @Package: com.spring.demo02
     * @ClassName: UserServiceImpl
     * @Author: Shengrui Zhang *@Date: 2022/2/12 14:42
     * @Version: 1.0 * /
    public class UserServiceImpl implements UserService{
        @Override
        public void add(a) {
            System.out.println("Added a user.");
        }
    
        @Override
        public void delete(a) {
            System.out.println("Deleted a user");
        }
    
        @Override
        public void update(a) {
            System.out.println("Updated a user");
        }
    
        @Override
        public void query(a) {
            System.out.println("Query a user"); }}Copy the code
  3. Demand comes, now we need to add a log function, how to achieve!

  • Idea 1: Add code to the implementation class.
  • Idea 2: Using proxies is the best way to do this without changing the business.
  1. Set up a proxy class to handle logging! The agent role

    package com.spring.demo02;
    
    / * * *@ProjectName: Spring5study
     * @Package: com.spring.demo02
     * @ClassName: UserServiceProxy
     * @Author: Shengrui Zhang *@Date: 2022/2/12 for *@Version: 1.0 * /
    public class UserServiceProxy implements UserService{
        private UserServiceImpl userService;
        public void setUserService(UserServiceImpl userService) {
            this.userService = userService;
        }
        public void add(a) {
            log("add");
            userService.add();
        }
        public void delete(a) {
            log("delete");
            userService.delete();
        }
        public void update(a) {
            log("update");
            userService.update();
        }
        public void query(a) {
            log("query");
            userService.query();
        }
        public void log(String msg){
            System.out.println("Executed."+msg+"Method"); }}Copy the code
  2. Test access class

    package com.spring.demo02;
    
    / * * *@ProjectName: Spring5study
     * @Package: com.spring.demo02
     * @ClassName: Client
     * @Author: Shengrui Zhang *@Date: 2022/2/12 when *@Version: 1.0 * /
    public class Client {
        public static void main(String[] args) {
            // Real business
            UserServiceImpl userService = new UserServiceImpl();
            / / the proxy class
            UserServiceProxy proxy = new UserServiceProxy();
            // Use proxy classes to implement logging!proxy.setUserService(userService); proxy.query(); }}Copy the code

OK, now we should have no problem with the proxy model, the key point is that we need to understand the idea;

The core idea in AOP is that we have implemented enhancements to the original functionality without changing the original code.

Talk about AOP: Vertical development, horizontal development

12.3 Dynamic Proxy

  • The role of a dynamic proxy is the same as that of a static proxy
  • The proxy class for dynamic proxy is dynamically generated. The proxy class for static proxy is written in advance.
  • Dynamic proxy can be divided into two types: dynamic proxy based on interface and dynamic proxy based on class
    • Interface based dynamic proxy —-JDK dynamic proxy
    • Class – based dynamic proxy – Cglib
    • Now more use is javasist to generate dynamic proxy. Baidu javasist
    • Here we use JDK native code to implement, the rest of the reason is the same!

JDK dynamic proxies need to know about two core classes: InvocationHandler and Proxy. Open the JDK help documentation to see

【InvocationHandler 】

/ / parameters
//proxy - the proxy instance that calls the method
//method - The method corresponds to invoking an instance of an interface method on a proxy instance. The declaration class of a method object will be the interface that the method declares, which can be the superinterface of the proxy interface that the proxy class inherits from the method.
//args - Contains an array of objects for method calls that pass the proxy instance's parameter values, or null if the interface method has no parameters. Parameters of primitive types are contained in instances of the appropriate primitive wrapper classes, such as java.lang.Integer or java.lang.Boolean
Object invoke(Object Proxy, method, Object[] args);Copy the code

【Proxy 】

// Generate the proxy class
public Object getProxy(a){
	return Proxy.newProxyInstance(this.getClass().getClassLoader(),
									rent.getClass().getInterfaces(),this);
}
Copy the code

Code implementation

The abstract and real characters are the same as before!

ISubject.java

package com.spring.demo03;

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo03
 * @ClassName: ISubject
 * @Author: Shengrui Zhang *@Date: 2022/2/12 15:52
 * @Version: 1.0 * /
// Abstract role: agent
public interface ISubject {
    public void shop(a);
}

Copy the code

Merchant.java

package com.spring.demo03;

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo03
 * @ClassName: Merchant
 * @Author: Shengrui Zhang *@Date: 2022/2/12 when *@Version: 1.0 * /
// The merchant's real role
public class Merchant implements ISubject {
    @Override
    public void shop(a) {
        System.out.println("Merchant will send the goods to the agent!!"); }}Copy the code

ProxyInvocationHandler.java

package com.spring.demo03;

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

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo03
 * @ClassName: ProxyInvocationHandler
 * @Author: Shengrui Zhang *@Date: 2022/2/12 15:57
 * @Version: 1.0 * /
public class ProxyInvocationHandler implements InvocationHandler {
    private ISubject iSubject;

    public void setiSubject(ISubject iSubject) {
        this.iSubject = iSubject;
    }

    // Generate the proxy class, focusing on the second argument, to get the abstract role to proxy! It used to be one role, but now it can represent a class of roles
    public Object getProxy(a){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                iSubject.getClass().getInterfaces(),this);
    }

    // proxy: method: method object of the invocation handler of the proxy class.
    // Process method calls on proxy instances and return results
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Core: Essence is realized by reflection!
        Object result = method.invoke(iSubject, args);
        returnresult; }}Copy the code

Client.java

package com.spring.demo03;

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo03
 * @ClassName: Client
 * @Author: Shengrui Zhang *@Date: 2022/2/12 16:01
 * @Version: 1.0 * /
public class Client {
    public static void main(String[] args) throws ClassCastException{
        // Real characters
        Merchant merchant = new Merchant();
        // The invocation handler for the proxy instance
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler();
        // Put the real character in!
        invocationHandler.setiSubject(merchant);
        // Dynamically generate the corresponding proxy class!ISubject proxy = (ISubject) invocationHandler.getProxy(); proxy.shop(); }}Copy the code

Core: a dynamic proxy, general proxy a certain kind of business, a dynamic proxy can proxy multiple classes, proxy is the interface

12.4 Deepen understanding

Use the dynamic proxy implementation to proxy UserService!

Can write a general dynamic proxy implementation of the class! Set all proxy objects to Object!

ProxyInvocationHandler template

package com.spring.demo03;

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

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo03
 * @ClassName: ProxyInvocationHandler
 * @Author: Shengrui Zhang *@Date: 2022/2/12 15:57
 * @Version: 1.0 * /
public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;

    public void setiSubject(Object target) {
        this.target = target;
    }

    // Generate the proxy class, focusing on the second argument, to get the abstract role to proxy! It used to be one role, but now it can represent a class of roles
    public Object getProxy(a){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);
    }

    // proxy: method: method object of the invocation handler of the proxy class.
    // Process method calls on proxy instances and return results
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        // Core: Essence is realized by reflection!
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String methodName){
        System.out.println("Executed."+methodName+"Method"); }}Copy the code

test

package com.spring.demo04;

import com.spring.demo02.UserService;
import com.spring.demo02.UserServiceImpl;

/ * * *@ProjectName: Spring5study
 * @Package: com.spring.demo04
 * @ClassName: Test
 * @Author: Shengrui Zhang *@Date: 2022/2/12 25 *@Version: 1.0 * /
public class Test {
    public static void main(String[] args) {
        // Real objects
        UserServiceImpl userService = new UserServiceImpl();
        // The invocation handler for the proxy object
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        // Set the object to be proxied
        pih.setTarget(userService);
        // Dynamically generate proxy classes!UserService proxy = (UserService)pih.getProxy(); proxy.delete(); }}Copy the code

Benefits:

Static proxy has it, static proxy does not have, it also has!

  • It can make our real role more pure and not focus on public things.
  • The common business is done by the agent, realizing the division of business.
  • Common services become more centralized and convenient when they are extended.
  • A dynamic proxy, typically for a certain type of service.
  • A dynamic proxy can proxy multiple classes, proxy is the interface!

After the language

The original intention of the director to write blog is very simple, I hope everyone in the process of learning less detours, learn more things, to their own help to leave your praise 👍 or pay attention to ➕ are the biggest support for me, your attention and praise to the director every day more power.

If you don’t understand one part of the article, you can reply to me in the comment section. Let’s discuss, learn and progress together!