I was stunned on the spot! The interviewer asked me the difference between the two proxy modes in Spring AOP

//Add V: BGM7756 can receive interview materials at the end of the article for free!

Basic introduction

Agent pattern is a structural design pattern. Provide a surrogate for an object to control access to that object. That is, the target object is accessed through the proxy object, and some processing is allowed before and after the request is submitted to the object.

The proxied object can be a remote object, an object with high creation cost, or an object requiring security control.

There are three main forms of proxy mode:

Static proxy: programmers create proxy classes or specific tools to automatically generate source code and then compile it. Of the proxy class before the program runs .class The file already exists
 Dynamic proxy( JDK Agent, interface agent): it is dynamically created by using the reflection mechanism when the program is running. The dynamic is generated when the program is running, not at compile time.
cglib Proxy (you can dynamically create objects in memory instead of implementing interfaces, which belongs to the category of dynamic proxy)

problem

Why control access to an object? For example: there is such a huge object that consumes a lot of system resources. You only need to use it occasionally, not always.

You can implement deferred initialization: create the object when it is actually needed. All clients of the object execute deferred initial code. Unfortunately, this is likely to lead to a lot of duplicate code.

Ideally, we want to put code directly into the class of the object, but this is not always possible: for example, the class may be part of a third-party closed library.

Solutions

The proxy mode suggests creating a new proxy class with the same interface as the original service object, and then updating the application to pass the proxy object to all the original object clients. After receiving the client request, the proxy class will create the actual service object and delegate all work to it.

The agent disguises itself as a database object and can handle the work of delaying initialization and caching query results without the knowledge of the client or the actual database object.

What are the benefits? If you need to do some work before and after the main business logic of the class, you can do this without modifying the class. Since the interface implemented by the proxy is the same as the original class, you can pass it to any client using the actual service object.

Agent mode structure

1. the Service Interface declares the Service Interface. The proxy must follow this interface to masquerade as a service object.
The Service class provides some useful business logic.
The Proxy class contains a reference member variable that points to the service object. After the agent completes its tasks (such as delayed initialization, logging, access control, caching, etc.), it passes the request to the service object. Typically, agents manage the entire lifecycle of the objects they serve.
The Client can interact with the service or proxy through the same interface, so you can use the proxy in all the code that needs the service object.

There are agent training for playing games and intermediary agencies for buying and selling houses. For example, general companies can also find agents for Internet advertising. The role of agent training, intermediary and advertising agencies here are agents.

Here is an example closer to programmers. For example, some abnormal companies do not allow us to use microblogs and watch videos in the company. We can restrict our access to these websites through a layer of agents.

No more nonsense. Let's start with a static proxy.
Static proxy

1. Define network interface

public interface Internet {
void connectTo(String serverHost) throws Exception;
}

2. True network connection

public class RealInternet implements Internet{

@Override
public void connectTo(String serverHost) throws Exception {
    System.out.println("Connecting to "+ serverHost);
}

}

3. Network agent of the company

      //+5: BGM7756, free access to information

public class ProxyInternet implements Internet {

//Target object, aggregated through interface
private Internet internet;

// Pass in the target object through the construction method
public ProxyInternet(Internet internet){
    this.internet = internet;
}
//Network blacklist
private static List<String> bannedSites;

static
      //+5: BGM7756, free access to information
{
    bannedSites = new ArrayList<String>();
    bannedSites.add("bilibili.com");
    bannedSites.add("youtube.com");
    bannedSites.add("weibo.com");
    bannedSites.add("qq.com");
}

@Override
public void connectTo(String serverhost) throws Exception {
    // Add restriction function
    if(bannedSites.contains(serverhost.toLowerCase()))
    {
        throw new Exception("Access Denied:"+serverhost);
    }
    internet.connectTo(serverhost);
}

}

4. Client authentication

      //+5: BGM7756, free access to information

public class Client {

public static void main(String[] args) {
    Internet internet = new ProxyInternet(new RealInternet());
    try {
        internet.connectTo("so.com");
        internet.connectTo("qq.com");
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

}

5. Output

Connecting to so.com
Access Denied:qq.com

You can't access entertainment websites, but you can use 360 search, SO Reliable, ha ha

Advantages and disadvantages of static proxy class
Advantages:

Without modifying the target object, you can extend the function of the target object through the proxy object

Proxy makes the client do not need to know what the implementation class is and how to do it. The client only needs to know the proxy (decoupling). For the above client code, RealInterner() can hide it in the application factory.
Disadvantages:

The proxy class and the delegate class implement the same interface, and the proxy class implements the same method through the delegate class. This leads to a lot of code duplication. If a method is added to the interface, all proxy classes need to implement this method in addition to all implementation classes. It increases the complexity of code maintenance.
Proxy objects only serve one type of objects. If you want to serve multiple types of objects. It is bound to proxy for every object. Static proxy is not competent when the program size is a little large.

Dynamic proxy

Static proxy will generate many static classes, so we need to find a way to complete all proxy functions through one proxy class, which leads to dynamic proxy.
JDK native dynamic proxy

The proxy object does not need to implement the interface, but the target object must implement the interface, otherwise the dynamic proxy cannot be used
 Proxy objects are generated through JDK of API(Reflection mechanism) to dynamically build proxy objects in memory

To implement the dynamic proxy mechanism in Java, you need java Lang.reflect Invocationhandler interface and java Lang.reflect Proxy class support
Coding

1. Network interface unchanged

public interface Internet {
void connectTo(String serverHost) throws Exception;
}

2. The real network connection will not change

public class RealInternet implements Internet{

@Override
public void connectTo(String serverHost) throws Exception {
    System.out.println("Connecting to "+ serverHost);
}

}

3. Dynamic proxy needs to implement InvocationHandler. Let's simplify it with Lambda expression

      //+5: BGM7756, free access to information

public class ProxyFactory {

/**
 * Maintain a target object
 **/
private Object target;

/**
 * Constructor, initializing the target object
 **/
public ProxyFactory(Object target) {
    this.target = target;
}

public Object getProxyInstance() {

    /**
     The proxy object target is passed in through parameters,
     Through target Getclass() Getclassloader() gets the ClassLoader object,
     Then through target Getclass() GetInterfaces () gets all the interfaces it implements,
     Then wrap the target into an object that implements the InvocationHandler interface.
     Through the newProxyInstance function, we get a dynamic proxy object.
     */
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if(bannedSites.contains(args[0].toString().toLowerCase()))
            {
                throw new Exception("Access Denied:"+args[0]);
            }
            //Reflection mechanism calls the method of the target object
            Object obj = method.invoke(target, args);
            return obj;
        }
    });
}

private static List<String> bannedSites;

static
      //+5: BGM7756, free access to information
{
    bannedSites = new ArrayList<String>();
    bannedSites.add("bilibili.com");
    bannedSites.add("youtube.com");
    bannedSites.add("weibo.com");
    bannedSites.add("qq.com");
}

}

4. Client

public class Client {

public static void main(String[] args) {
    Internet internet = new ProxyInternet(new RealInternet());
    try {
      //+5: BGM7756, free access to information
        internet.connectTo("360.cn");
        internet.connectTo("qq.com");
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

}

In the dynamic proxy mode, all function calls will eventually be forwarded by the invoke function, so we can do some operations we want to do here, such as logging system, transaction, interceptor, permission control, etc.
cglib proxy

Both the static proxy and JDK proxy modes require the target object to implement an interface. However, sometimes the target object is only a separate object and does not implement any interface. At this time, you can use the target object subclass to implement the proxy, which is cglib proxy.

cglib(Code Generation Library)Is based on ASM Bytecode generation library, which allows us to modify and dynamically generate bytecode at runtime. cglib The proxy is implemented by inheritance. It is widely used by many AOP For example, our Spring AOP. 
cglib At the bottom of the package is the bytecode processing framework ASM To convert bytecode and generate new classes.
cglib Proxy is also called subclass proxy. It builds a subclass object in memory to extend the function of the target object.

Coding

Add cglib dependency

cglib cglib 3.3.0

1. No interface required

public class RealInternet{

public void connectTo(String serverHost) {
    System.out.println("Connecting to "+ serverHost);
}

}

2. Agent factory

public class ProxyFactory implements MethodInterceptor {

private Object target;

public ProxyFactory(Object target){
    this.target = target;
}
      //+5: BGM7756, free access to information

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    System.out.println("cglib Agent start, logic can be added");
    Object obj = method.invoke(target,objects);
    System.out.println("cglib Agent end");
    return obj;
}


public Object getProxyInstance(){
    //Tool class, similar to the Proxy class of JDK dynamic Proxy
    Enhancer enhancer = new Enhancer();
    //Set parent class
    enhancer.setSuperclass(target.getClass());
    //Set callback function
    enhancer.setCallback(this);
    //Create a subclass object, the proxy object
    return enhancer.create();
}

}

3. Client

public class Client {

public static void main(String[] args) {

    //Target object
    RealInternet target = new RealInternet();
    //Gets the proxy object and passes the target object to the proxy object
    RealInternet internet = (RealInternet) new ProxyFactory(target).getProxyInstance();
    internet.connectTo("so.cn");
}

}
//+5: BGM7756, free access to information

4. Output

cglib proxy starts, logic can be added
Connecting to so.cn
cglib agent end

Proxy mode is suitable for application scenarios

There are many ways to use the proxy pattern. Let's take a look at the most common.

Delayed initialization (virtual proxy): if you have a heavyweight service object that is used occasionally, and keeping the object running all the time will consume system resources, you can use the proxy mode. You do not need to create this object at the start of the program. You can delay the initialization of the object until it is really needed.
Access control (protection proxy): if you only want a specific client to use a service object, the object here can be a very important part of the operating system, while the client is a variety of started programs (including malicious programs). In this case, you can use the proxy mode. The proxy can pass the request to the service object only if the client credentials meet the requirements.
Execute remote service locally (remote proxy): This is applicable when the service object is located on a remote server. In this case, the proxy passes the client request through the network and is responsible for handling all the complex details related to the network.
Logging request (logging agent): applicable when you need to save the request history for the service object. The agent can record before passing the request to the service.
Cache request results (cache proxy): This is applicable to caching the client request results and managing the cache life cycle, especially when the volume of the returned results is very large. The proxy can cache the same results required by repeated requests, and can also use the request parameters as the key values of the index cache. For example, when requesting resources such as pictures and files, go to the proxy cache first. If not, go to the public network and cache them to the proxy server
 Smart reference: you can destroy a heavyweight object immediately when no client is using it. The agent will record all clients that have obtained the service object or its results. From time to time, the agent iterates through the clients to see if they are still running. If the corresponding client list is empty, the agent will destroy the service object and release the underlying system resources. The agent can also record whether the client has modified the service object. Other clients can also reuse unmodified objects.

Proxy mode in AOP

The main implementation technologies of AOP (aspect oriented programming) are Spring AOP and AspectJ

The underlying technology of AspectJ is the static agent. The aspect is written in a specific language supported by AspectJ, and compiled with a command to generate a new agent class. The agent class enhances the business class. This is enhanced at compile time. Compared with the run-time enhancement mentioned below, the performance enhanced at compile time is better. (the AspectJ static proxy does not need to manually write a proxy class for each target class as we mentioned earlier. The AspectJ framework can generate the "proxy class" of the target class at compile time. A colon is added here because it does not actually generate a new class, but directly compiles the proxy logic into the target class.)

Spring AOP uses a dynamic proxy to enhance business methods during runtime, so no new classes will be generated. For dynamic proxy technology, spring AOP provides support for JDK dynamic proxy and CGLib.

By default, Spring uses JDK Proxy for classes that implement interfaces. Otherwise, it uses CGLib. However, you can specify by configuration that Spring AOP generates proxy classes through CGLib.

The specific logic is at org Springframework Aop Framework In the defaultaopproxyfactory class, the method used to generate the source code is determined by AopProxy according to the configuration of the AdvisedSupport object, as follows:

      //+5: BGM7756, free access to information

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
public DefaultAopProxyFactory() {
}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
        return new JdkDynamicAopProxy(config);
    } else {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
        } else {
            //If the target class is an interface and a proxy class, use JDK dynamic proxy class; otherwise, use Cglib to generate proxy class
            return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
        }
    }
}

      //+5: BGM7756, free access to information
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
}

}

Due to the limited space, the information and pictures will not be released one by one. If you need help, please add the wechat BGM7756 to get the information for free. I hope it can help you find a job!

Tags: Java Spring Interview SpringAop

Posted by magi on Mon, 30 May 2022 20:10:01 +0530