Learning of Agent Mode of Java23 Design Patterns

Source link (Gitee code cloud): https://gitee.com/oldou/javadesignpatterns
Here is the source code of Java23 design patterns and blog tutorials that I have compiled. The blog tutorial introduces various implementations of Java23 design patterns. And application scenarios, it is very suitable for learning and improving our design thinking. If it is helpful to everyone, please remember to star and give the author some spiritual support. Your star is the motivation for me to write a better blog. Thank you.

Proxy pattern

In the Proxy Pattern, one class represents the function of another class. This type of design pattern is a structural pattern.

In the proxy mode, we create objects with existing objects in order to provide functional interfaces to the outside world.

Core role:

  • Through the proxy, control the access to the object!
  • You can control in detail the method of accessing a certain object (of a certain type), do pre-processing before calling this method, and do post-processing after calling this method. (Ie: the micro realization of AOP!)
  • Implement the unified process code to be processed in the agent class.

AOP(Aspect Oriented Programming)Aspect-oriented programming) core implementation mechanism!

Core role

  • Abstract role
    -a public external method to define agent roles and real roles

  • Real role
    -to implement abstract roles, define the business logic to be implemented by real roles, for agent roles to call.
    – Pay attention to the real business logic!

  • Agent role
    -to achieve abstract role, it is the agent of real role, the abstract method is realized through the business logic method of real role, and you can attach your own operations.
    – Put unified process control into the agent role

Application scenario

  • Security proxy: shield direct access to real roles.
  • Remote agent: handle remote method invocation (RMI) through the agent class
  • Lazy loading: Load the lightweight proxy object first, and then load the real object.
  • For example, if you want to develop a large document viewing software, there are large pictures in a large document. It is possible that a picture has 100MB. It is impossible to display all the pictures when opening the file, so that you can use the proxy mode when you need to view the pictures. When, use proxy to open the big picture.

classification

(1) Static proxy (statically define proxy class)

(2) Dynamic proxy (dynamically generated proxy class)

  • Dynamic proxy that comes with JDK
  • Javaassist bytecode manipulation library implements dynamic proxy
  • CGLIB dynamic agent
  • ASM (underlying instructions, poor maintainability)

This article only introduces the use of static proxy mode and JDK dynamic proxy mode.

Case

For example, we take the renting in our life as a case. We usually find an intermediary when we rent a house, and the intermediary is an agent. He represents the landlord to help him rent out the house. The landlord only needs to provide the rented house, no other The landlord and the intermediary are ultimately renting out the house, so they have a common interface. Let’s use code to implement it.
Insert picture description here

Static proxy mode

Provide interface for renting:

/**
 * 租房
 */
public interface Rent {
    
    
    public void rent();//租房这个事情
}

The real role: the landlord

/**
 * 真实的角色:房东
 * 需要将房子租出去
 */
public class FangD implements Rent {
    
    
    @Override
    public void rent() {
    
    
        System.out.println("出租XXX房,两室一厅....");
    }
}

Agency role: intermediary

/**
 * 代理角色:中介
 * 需要代理房东去租房,因此也要实现租房的方法
 */
public class Proxy implements Rent {
    
    
    private FangD fd;
    //提供一个房东的有参构造
    public Proxy(FangD fd) {
    
    
        this.fd = fd;
    }
    public Proxy(){
    
    }

    @Override
    public void rent() {
    
    
        seeHouse(); //中介这里扩展的操作  看房
        fd.rent();//调用房东的租房方法
        hetong();//签合同
        fare();//收取中介费
    }

    //看房
    public void seeHouse(){
    
    
        System.out.println("中介带你看房..");
    }
    //收中介费
    public void fare(){
    
    
        System.out.println("中介收你中介费100元..");
    }
    //签合同
    public void hetong(){
    
    
        System.out.println("签合同...");
    }
}

Client: Renter

/** 静态代理模式
 * 真实的人:需要租房的人--客户
 */
public class Client {
    
    

    public static void main(String[] args) {
    
    
        //房东要出租房子
        FangD fd = new FangD();

        //代理,中介要帮房东出租房子,并且中介还可以做一些附属操作
        Proxy proxy = new Proxy(fd);

        //不用找房东,直接找中介租房
        proxy.rent();
    }

}

Run output:
Insert picture description here

Realization of static proxy mode in business

When we usually use the proxy mode, we need to add the function of adding a log to the business we perform, and it is a taboo to change the source code in the company, so we need to add the log to the proxy mode to expand horizontally, as shown below :

Business interface:

public interface UserService {
    
    
    void add();
    void delete();
    void update();
    void query();
}

Implementation class of business interface:

public class UserServiceImpl implements UserService {
    
    
    @Override
    public void add() {
    
    
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
    
    
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
    
    
        System.out.println("修改了一个用户");
    }

    @Override
    public void query() {
    
    
        System.out.println("查询了一个用户");
    }
}

Business agent (to realize the increase of log function):

/**
 * 代理类,我们在此添加一个日志的功能
 */
public class UserServiceProxy implements UserService {
    
    
    private UserServiceImpl userService;
    public void setUserService(UserServiceImpl userService) {
    
    
        this.userService = userService;
    }
    @Override
    public void add() {
    
    
        log("add");
        userService.add();
    }
    @Override
    public void delete() {
    
    
        log("delete");
        userService.delete();
    }
    @Override
    public void update() {
    
    
        log("update");
        userService.update();
    }
    @Override
    public void query() {
    
    
        log("query");
        userService.query();
    }
    public void log(String msg){
    
    
        System.out.println("[Debug]-->使用了"+msg+"方法");
    }

}

test:

public class Client {
    
    
    public static void main(String[] args) {
    
    
        UserServiceImpl userService = new UserServiceImpl();

        UserServiceProxy proxy = new UserServiceProxy();
		
        proxy.setUserService(userService);

        proxy.add();
    }

}

Output:
Insert picture description here

Advantages of static proxy :

  • The landlord only needs to find an agent to rent the house, and the other operations are left to the agent
  • This can make the operation of the real role more pure, without having to pay attention to some public services
  • Public business is handed over to the agent role to realize the division of work
  • Convenient centralized management when public business expands
  • We extend some functions to the project without changing the original business. The agency model is very suitable, which is equivalent to horizontal development.
    Insert picture description here

Disadvantages :

  • A real role will produce an agent role, the amount of code will double, and the development efficiency will be lower

Dynamic proxy mode

  • Dynamic agents have the same roles as static agents;
  • The proxy class of the dynamic proxy is dynamically generated, not written directly by us;
  • Dynamic agents are divided into two categories: interface-based dynamic agents and class-based dynamic agents;

The implementation of the dynamic proxy mode is mainly as follows:

Based on the interface: JDK dynamic proxy
Based on the interface: java bytecode to achieve dynamic proxy (javasist)

Based on class: CGlib dynamic agent

ASM (underlying instructions, poor maintainability)

Advantages of dynamic proxy (compared to static proxy) : All
methods declared in the abstract role (interface) are transferred to a centralized method of the call processor, so that we can handle many methods more flexibly and uniformly.

The following are introduced one by one.

JDK implements dynamic proxy

The dynamic proxy of JDK has two core classes: Proxy and InvocationHandler

  • java.lang.reflect.Proxy: Role: dynamically generate proxy classes and objects

  • java.lang.reflect.InvocationHandler(Processor interface)
    • The proxy access to the real role can be achieved through the invoke method.
    • Specify the corresponding processor object every time a proxy object object is generated through Proxy

Let's take the case of renting a house to realize the dynamic agency of the following JDK.

Code test

Rental interface:

/**
 * 租房
 */
public interface Rent {
    
    
    public void rent();//租房这个事情
}

The real role: the landlord

/**
 * 真实的角色:房东
 * 需要将房子租出去
 */
public class FangD implements Rent {
    
    
    @Override
    public void rent() {
    
    
        System.out.println("出租XXX房,两室一厅....");
    }
}

Automatic generation of proxy classes (emphasis):

/**
 * 这个类会自动的生成代理类
 */
public class ProxyInvocationHandler implements InvocationHandler {
    
    
    //被代理的接口
    private Rent rent;
    public void setRent(Rent rent) {
    
    
        this.rent = rent;
    }

    //生成得到代理类
    //newProxyInstance:返回代理类的一个实例
    public Object getProxy(){
    
    
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                rent.getClass().getInterfaces(),this);
    }


    //处理代理实例并返回结果
    //proxy指的是代理类
    //method指的是被代理的方法
    //args指的是该方法的参数对象
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        //动态代理的本质就是使用反射机制实现的
        seeHouse(); //扩展操作
        Object result = method.invoke(rent, args);
        writeHeTong();//扩展操作
        return result;
    }

    //扩展操作
    public void seeHouse(){
    
    
        System.out.println("中介带你看房子");
    }
    public void writeHeTong(){
    
    
        System.out.println("签署合同");
    }
}

Client:

/**
 * 客户
 */
public class Client {
    
    

    public static void main(String[] args) {
    
    
        //真实角色
        FangD fd = new FangD();

        //代理角色:现在是没有
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //通过调用程序处理角色来处理我们要调用的接口对象
        pih.setRent(fd);
        //下面的proxy就是动态生成的代理对象
        Rent proxy = (Rent) pih.getProxy();
        proxy.rent();

    }

}

Test output:
Insert picture description here

Summary :
Dynamic proxy steps:
1. Create a class that implements the interface InvocationHandler, which must implement the invoke method
2. Create the proxy class and interface
3. Create it through the Proxy static method newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) A proxy class
4. Call methods through the proxy

It can be seen from the dynamic proxy implementation of JDK that the reflection mechanism is actually used.
First create your own invocation handler by implementing the InvocationHandler interface, then create a dynamic proxy class by specifying a ClassLoader object and a set of interfaces for the Proxy class, and then obtain the constructor of the dynamic proxy class through the reflection mechanism. The only parameter type is the invocation process. The interface type of the processor, and finally the dynamic proxy class instance is created through the constructor, and the processor object is called as a parameter during construction.

Realization of JDK dynamic proxy in business

Let's take the above function of adding logs to the business as an example, and at the same time make certain modifications to our invocation processor code into a form equivalent to a tool class, as shown below:
ProxyInvocationHandler invocation processor:

/**
 * 这个类会自动的生成代理类
 *
 */
public class ProxyInvocationHandler implements InvocationHandler {
    
    
    //被代理的目标接口
    private Object target;
    public void setTarget(Object target) {
    
    
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
    
    
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);
    }


    //处理代理实例并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        //动态代理的本质就是使用反射机制实现的
        log(method.getName());
        Object result = method.invoke(target, args);

        return result;
    }

    //扩展操作--日志
    public void log(String msg){
    
    
        System.out.println("[Debug]--->执行了"+msg+"方法");
    }

}

Client:

public class Client {
    
    

    public static void main(String[] args) {
    
    
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();

        //代理角色  不存在
        ProxyInvocationHandler pih = new ProxyInvocationHandler();

        //设置要代理的对象
        pih.setTarget(userService);

        //动态的为其生成代理对象
        UserService proxy = (UserService)pih.getProxy();

        proxy.add();
    }

}

Output:
Insert picture description here

Application scenarios in the development framework

  • Implementation of interceptor in struts2
  • Database connection pool closing processing
  • Implementation of Delayed Loading in Hibernate
  • Implement interceptor plug-in in mybatis
  • Implementation of AspectJ
  • Implementation of AOP in spring
    • log interception
    • declarative transaction processing
  • web service
  • RMI remote method call
  • In fact, any choice of technical framework will use proxy mode

Guess you like

Origin blog.csdn.net/weixin_43246215/article/details/108599790