Design Mode (15) Structural Mode-Agent Mode: Static, Dynamic Agent, Cglib Agent

Foreword

The structural pattern of the design pattern is the last and the most difficult one (I feel during the learning process): the
agent pattern. The pre-knowledge of learning the agent pattern: Java reflection

First review the previous structural patterns:

  1. Adapter mode: create an adapter class and convert the class that the customer cannot use into the class that the customer needs (charger: 220V-> 5V)
  2. Bridge mode: build a "bridge" by means of aggregation, and simply combine the changes of multiple dimensions of a thing (painting requires multiple colors and brush size models)
  3. Decorating mode: "Doll pattern", which introduces the modified person to the decorator, and dynamically adds functions to the modified person (add sugar and milk to the coffee)
  4. Combination mode: recursive idea, inheriting the same class from multiple levels of the tree structure of customer needs, treating container objects (upper nodes) and leaf objects (leaf nodes) consistently, and maintaining a container to store lower nodes in the container object Tree structure (multi-level description of Linux directory)
  5. Appearance mode: Set an appearance role to concentrate the functions of the subsystem, so that the client class can simply call the appearance role method to achieve complex subsystem functions (a remote control for home theater can control multiple instruments)
  6. Flyweight model: Flyweight factory maintains a Flyweight pool to ensure the reuse of specific shared roles (String and constant pool)

This article will: the concept of proxy mode-"static proxy-" dynamic proxy-"Cglib proxy-" summary

Problems in reality

A client does not want or cannot directly refer to an object, in this case, an indirect reference can be achieved through a third party called a "proxy"

The proxy object can act as an intermediary between the client and the target object , and can remove content and services that the client cannot see or add additional services that the client needs through the proxy object

The proxy mode is very common, for example:

Take a train when you travel, you do n’t have to go to the train station to buy a train ticket
Insert picture description here

You can buy it through the 12306 website or go to the train ticket agency

This is the proxy mode: the customer does not want to go directly to the train station (using an object), but buys a ticket at 12306 (using the agent role to call the original object's method)

Proxy mode

Proxy Pattern : Provide a proxy for an object, and the proxy object controls the reference to the original object. The proxy mode in English is called Proxy or Surrogate

Proxy mode structure:
Insert picture description here

The role of proxy mode:

  • Abstract theme role (Subject): Declares business methods implemented by real theme and proxy objects through interfaces or abstract classes.
  • Real Subject: Realizes the specific business in the abstract theme, is the real object represented by the proxy object, and is the object to be referenced eventually.
  • Proxy role (Proxy): provides the same interface as the real theme, which contains references to the real theme, it can access, control or extend the functionality of the real theme.

A bit similar to appearance mode, the difference from appearance mode:

Appearance mode is a method of concentrating complex subsystem functions into appearance roles. Clients only need to use appearance roles to complete complex functions (such as home theater remote control press on: lights will turn off, screen will turn on, DVD will turn on , The projector is turned on), focusing on the subsystem function concentration and client simplification

The proxy mode is to control the reference of the original object through the role of the agent for the objects that the customer cannot and do not want to use. The focus is on calling the original object through a third party to reduce coupling

Static proxy

Static proxy is relatively simple, just realize the ticket purchase case

package com.company.Structural.Proxy;
//抽象类:定义火车站功能
interface Station {
    public void buyTicket();
}
//火车站售票处
class TrainStation implements Station{

    @Override
    public void buyTicket() {
        System.out.println(" 购买火车票。。。");
    }
}
//代购火车票:12306
class WebSite12306 implements Station{
    //内置一个火车站对象
    private Station station = new TrainStation();

    @Override
    public void buyTicket() {
        System.out.println(" 打开12306。。。");
        station.buyTicket();
        System.out.println(" 关闭12306。。。");
    }
}
class User{
    public static void main(String[] args) {
        WebSite12306 webSite12306 = new WebSite12306();
        webSite12306.buyTicket();
    }
}

Insert picture description here

There is a method to buy train tickets inside 12306 (built-in train station object). Customers buying train tickets through 12306 are essentially tickets bought at the train station, but only through the third-agent role

Static proxy to dynamic proxy

Defects of static agents

Obviously, a static proxy implements its own method by combining an original object and then calling the original object's method. Such a defect is that an original object requires a proxy object, and the extension needs to modify the source code, which does not meet the "opening and closing principle"
and the object Must be known so that the object can be combined

For example, if you add an airline ticket sales office, the proxy object needs to have a built-in airline ticket sales object, which can only be added by modifying the source code, or creating a new proxy object

The solution to this problem is dynamic proxy

Dynamic proxy

Dynamic proxy is also called JDK proxy and interface proxy.
It has the following characteristics:

  1. The proxy role does not need to implement the interface, but the real theme role must implement the interface (otherwise dynamic proxy cannot be used)
  2. The generation of the proxy object is realized through reflection in the JDK, and the proxy role is dynamically built in memory
  3. The package where the proxy class is located is java.lang.reflect, which implements the Proxy.newProxyInstance method in Java reflection

Dynamic proxy implementation

Simulate the ticket purchase process at 12306 with dynamic agents

package com.company.Structural.Proxy;

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

//抽象类:定义火车站功能
interface Station {
    public void buyTicket();
}
//火车站售票处
class TrainStation implements Station{

    @Override
    public void buyTicket() {
        System.out.println(" 购买火车票。。。");
    }
}
//代购火车票:12306
class WebSite12306{
    //目标对象
    private Object target;

    public WebSite12306(Object target) {
        this.target = target;
    }

    //生成代理对象
    public Object getProxyInstance() {
        //事件处理,传入目标对象的方法,可以自定义额外方法
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("---------------打开12306---------------");
                Object result = method.invoke(target, args);
                System.out.println("---------------关闭12306---------------");
                return result;
            }
        };
        //通过反射机制
        /*
        * public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
          1. ClassLoader是目标对象的类加载器
          2. interfaces是目标对象实现的接口,用泛型方式确认类型
          3. InvocationHandler是事件处理(自己编写),用于触发事件处理器方法,当前执行的目标对象的方法会作为参数传入
        * */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler);

    }
}
class User{
    public static void main(String[] args) {
        //目标对象
        Station trainStation = new TrainStation();
        //创建代理工厂
        WebSite12306 webSite12306 = new WebSite12306(trainStation);
        //得到代理角色
        Station proxyInstance = (Station) webSite12306.getProxyInstance();
        //执行方法
        proxyInstance.buyTicket();
    }
}

Insert picture description here

It can be seen that the dynamic proxy obtains the method of the target object through reflection. At this time, any type of target object can be implemented.

This involves the knowledge of reflection, a little learning

Dynamic proxy related

We get the class loading object of the target object through Proxy, implement the interface, and then write the event processing object to complete the dynamic proxy. Among these, we should pay attention to:

Proxy.newProxyInstance

Proxy is a proxy class, a class that dynamically creates a proxy object, it provides some methods
Insert picture description here

One of the most used is the newProxyInstance method, which returns a dynamic proxy object

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

Insert picture description here
It passed three parameters: ClassLoader, Class <?> [] Interfaces, InvocationHandler

ClassLoader knows that it is a class loader object, which decides which loader to use to process the object.
What we pass in is target.getClass().getClassLoader()the class loader of the target object

Interfaces is a collection of interfaces implemented by the target object. Use generic methods to confirm the type Class <?> []
This parameter is a set of interfaces of the target object to be proxied . If I provide a set of interfaces to it, then the proxy object declares Implemented the interface (polymorphism), so that I can call the methods in this group of interfaces, we target.getClass().getInterfaces()obtained the interface implemented by the target object

InvocationHandler is an event processing interface, which is an event processing object written by ourselves (the method of the target object is included here)

Insert picture description here
This interface defines an invoke method specification

InvocationHandler

The invoke method defined in the InvocationHandler interface passes 3 parameters, and the return value is Object

 public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

When there are multiple proxy classes, each proxy class will be associated with a handler. When we call a method through the proxy object, the call of this method will be forwarded to the invoke method of the interface of InvocationHandler to call, namely The method of executing the proxy object will be replaced by the execute invoke method

This can be a good extension of the proxy mode system (no need to care what method is passed in the end)

Let's take a look at these three parameters: Object proxy, Method method, Object [] args

Object proxy : As you can see from the name, this is the target object we need to proxy

Method method : The Method object to call a method of the target object, proxyInstance.buyTicket();the buyTicket method called in the above case is this Method object

Can be viewed through Debug
Insert picture description here

It will contain various attributes of Method

Object [] args : the parameters passed in the above method and the parameters required to call the target object. The above case does not show, but you can modify Debug to try

Need to add name in the buyTicket method
Insert picture description here

Execution method: proxyInstance.buyTicket("zhangsan");
you can see the "zhangsan" string added to the args array
Insert picture description here

Proxy0

We can output what the class obtained by getProxyInstance () is.
Insert picture description here
Add a getClass method

Insert picture description here

After execution, you can see that the Class name is: com.company.Structural.Proxy.$Proxy0
Why is the Proxy. $ Proxy0 class returned?

The proxy object created by Proxy.newProxyInstance is an object dynamically generated when the JVM is running. The naming method starts with $, proxy is in the middle, and the last number indicates the label of the object$Proxy0

As for the previous: it com.company.Structural.is my package name
Proxybecause we are using the method of the Proxy class

Looking at our Method name isProxy.Station.buyTicket()

Insert picture description here
This is because our method is executed from the getProxyInstance method of the proxy class to the invoke object of the handler object in the newProxyInstance method and the handler
accepts the target object, indicating that the object is executed, and the invoke method in the handler will be called to execute the target object. The corresponding method

Therefore, the object name of Method is: Proxy.Station.buyTicket()
Proxy represents the newProxyInstance method of the called Proxy class, Station is the interface we write, and it is the type of our proxy object forced, buyTicket is the specific method used

Station type

Station proxyInstance = (Station) webSite12306.getProxyInstance();

When we get the proxy object, we use the type forced to Station, why can we force it like this?

The parameter passed by Proxy.newProxyInstance: Class <?> [] Interfaces represent the interface implemented by the target object, through this parameter, our proxy object will also implement this interface

This is why I said earlier: the agent role does not need to implement the interface, but the real theme role must implement the interface

Cglib proxy

Why use Cglib proxy

Note: In the previous dynamic proxy, the target object should implement the interface. The proxy object implements the interface internally through the interfaces parameter of Proxy.newProxyInstance

But in many cases, the target object does not implement the interface, so the dynamic proxy cannot be used. . .

At this time, the proxy can be implemented through the subclass of the target object, which is the Cglib proxy

The Cglib proxy is also called a subclass proxy. It is to build a subclass object in memory to achieve the function expansion of the target object . The Cglib proxy is also a dynamic proxy

Cglib is a powerful, high-performance code generation package, it can extend Java classes and implement Java interfaces during operation, be used many AOP framework, such as packaging Cglib Spring AOP is used, interception implementation
Cglib underlying package by using Bytecode processing framework ASM to convert bytecode and generate new classes

Cglib proxy implementation

First introduce 4 jar packages
Insert picture description here

Simple implementation of the above ticket purchase case

package com.company.Structural.Proxy.Cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

class TrainStation{
    public void buyTicket(String name) {
        System.out.println(name+" 购买火车票。。。");
    }
}

class WebSite12306 implements MethodInterceptor {
    //维护一个目标对象
    private Object target;
    //构造器
    public WebSite12306(Object target) {
        this.target = target;
    }
    //返回代理对象
    public Object getProxyInstance(){
        //创建工具类
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调函数,自己回调
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("-----------Cglib:12306开启-----------");
        Object result = method.invoke(target, args);
        System.out.println("-----------Cglib:12306关闭-----------");
        return result;
    }
}
class Client{
    public static void main(String[] args) {
        //创建目标对象
        TrainStation trainStation = new TrainStation();
        //获得代理对象
        TrainStation proxyInstance = (TrainStation)new WebSite12306(trainStation).getProxyInstance();
        //执行代理对象方法
        proxyInstance.buyTicket(" zhangsan ");
    }
}

Insert picture description here

It can still be done, check the running sequence through Debug

getProxyInstance returns the proxy object:
Insert picture description here
execute the proxy method:

Insert picture description here
Run the rewritten execution method:
Insert picture description here

And execute the method passed by the target object

The Cglib agent is similar to the dynamic agent, and has been improved on the basis of the dynamic agent

select

Which agent to choose in AOP programming:

  1. The target object needs to implement the interface, using JDK proxy
  2. The target object does not need to implement an interface, use Cglib proxy

Proxy mode variant

The static proxy, dynamic proxy, and Cglib proxy mentioned above are the most commonly used proxy modes.

There will be some variants of the proxy mode for different application environments (but essentially static or dynamic proxy)

  1. Firewall proxy The
    internal network penetrates the firewall through the proxy to achieve access to the public network.
  2. Cache proxy: For example, when requesting resources such as image files, go to the cache proxy first. If the resource is retrieved, then ok. If the resource cannot be retrieved, go to the public network or database, and then cache.
  3. Remote agent
    The local representative of the remote object, through which you can call the remote object as a local object. Remote agents communicate information with real remote objects through the network.
  4. Synchronization agent: mainly used in multithreaded programming to complete the synchronization work among multiple threads
  5. Virtual agent: When the loading of an object is very resource intensive, the advantages of virtual agent are very obvious. The virtual proxy mode is a memory saving technique. Those objects that take up a lot of memory or process complex objects will be deferred until they are used.
    When the application starts, proxy objects can be used instead of real object initialization, saving memory usage and greatly speeding up system startup time

These variants are based on dynamic agents and extend in different environments

to sum up

  • The proxy mode is to create a proxy role, the client does not want or can not directly use the target object, the client controls the reference to the target object through the proxy object
  • Agent mode is divided into static agent mode and dynamic agent mode, and dynamic agent mode can be divided into JDK agent and Cglib agent
  • Static proxy is the combination of the target object inside the proxy object and internal call of the target object method. The client controls the reference to the target object through the proxy object
  • The disadvantage of static proxy is that the target object needs to be clarified, and the target object needs to be combined into the proxy object, which cannot be modified or extended (the source code of the proxy object needs to be modified), and the dynamic proxy solves this problem.
  • In the dynamic proxy, the JDK proxy uses Java reflection and proxy. The newProxyInstance method of the Proxy can obtain the class loader and implemented interface of the target object, and write the event processing by itself, and encapsulate the method of the target object required by the client in the invoke method. Implement proxy objects
  • The JDK proxy requires the target object to implement the interface (the proxy object's internal methods implement the target object's interface), but many classes do not need to implement the interface. For these classes, the JDK proxy cannot handle it, and it is done through the Cglib proxy
  • The Cglib agent uses the bytecode processing framework ASM to process bytecode to form a new class, build a subclass object of the target object in memory, and complete the function expansion of the target object
  • Most AOP frameworks such as Spring AOP complete the AOP function through the Cglib proxy
Published 121 original articles · won 31 · views 7869

Guess you like

Origin blog.csdn.net/key_768/article/details/105371084