Java basics - static proxy and dynamic proxy

Dynamic proxy:

Before understanding dynamic proxies, first have an understanding of proxies.

The proxy pattern is one of the common design patterns in Java. The so-called proxy mode means that the client does not directly call the actual object, but indirectly calls the actual object by calling the proxy.

For example: when you buy a train ticket, you don’t directly spend money to buy it, but advance the money to the ticket-snatching software in advance, so that the ticket-snatching software can buy it for you. is your agent

Proxy objects control access to proxied objects:

This is the generic model diagram for the agent

  • Subject: defines the common interface or abstract class of the proxied role and the proxy role, that is, the common interface opration() is defined in the subject;

  • Realsubject: Implements or inherits abstract subject roles, and defines implementations that implement specific business logic .

  • Proxy: That is, the proxy, porxy holds the reference control and implementation of Realsubject. And has its own processing logic.

There are two types of proxies, static and dynamic. First understand static proxies, and after knowing their shortcomings, and then understand dynamic proxies, you will be enlightened.

The role of static proxy:

Static proxies are usually used to extend the original business logic. For example, a class that holds a second-party package and calls some of its methods. Then for some reason, such as logging, printing method execution time, but it is not easy to write these logics into the method of the second-party package. So you can create a proxy class to implement the same method as the second-party method. By letting the proxy class hold the real object, and then calling the proxy class method in the original code, you can achieve the purpose of adding the business logic we need.

Implementation of static proxy:

It is convenient to understand that the introduced Proxy is defined by itself, and the Proxy provided in java.reflect will be used in the following dynamic proxy.

package proxy;  
//将业务层抽象出来的接口.
public interface Subject {  
    void doSomething();
}


package proxy;

//真实对象,也就是被代理者,理解为你自己就可以了,要进行买票行为.
public class RealObject implements Subject{
    
    @Override
    public void doSomething() {

        System.out.println("这里是真实对象");

    }
}


package proxy;

//代理者,进行代理事务的人,理解成抢票软件,要代替你进行买票行为.
public class Proxy implements  Subject{

    private Subject realObject;

     Proxy(Subject realObject){
        this.realObject=realObject;
        //从这里知道需要代理的人是谁
    }
    
    @Override
    public void doSomething() {
        System.out.println("这里是代理对象");
        //可以在调用真实对象前增加操作
        //例如在开抢前告诉你,抢票要开始了.
        realObject.doSomething();//在这里调用真实的代理对象
        //可以在调用真实对象后增加操作.
        //在抢票结束后,告诉你成功或者失败.
    }
    
}

implement:

package proxy;

public class ProxyTest {


    public static void main(String[] args){

        RealObject realObject =new RealObject();
        realObject.doSomething();//被代理对象做的事,或者说委托人想要做的事

        System.out.println("-----------------");
        Proxy proxy =new Proxy(new RealObject());//告知代理对象被代理对象是谁,或者说告诉执行者委托人要做什么.
        proxy.doSomething();//通过代理对象调用被代理对象,实现代理.

        /*
        代理和被代理是不是有点晕,换一种说法来说.
        以DOTA为例:
        大哥本来要自己拉野,忽然发现一大波线袭来,于是就和酱油说,帮我拉两波野,一会带你喝汤! 大哥就是被代理者
        酱油说: 是大哥! 酱油在去拉野的路上,吃了赏金符,拉完野之后配合队友杀了一波人. 酱油就是代理者
        吃赏金符就是预处理.
        杀人就是结果处理.
         */
    }

}

Have you noticed that although this forms an agency behavior, the writing style is hateful and the coupling degree is very high. Now it is a train ticket. If there are a series of demands such as plane tickets, concert tickets, etc. and a series of employers, it will lead to The amount of code in the proxy class is getting larger and larger, and there is a danger of duplicate names, which is the disadvantage of static proxy.

In order to solve this problem, the big guys invented the method of dynamic proxy.
JAVA provides us with the interface of dynamic proxy, which is very convenient to use. Let's learn about it below.

The function to be extended needs to be written in an InvocationHandler implementation class:

The public functions to be extended by the proxy class are implemented in the invoke method in this Handler.

Disadvantages of static proxy:
There are ten different RealObjects, and the methods we want to proxy are different, than the proxy methods: doSomething, doAnotherThing, doTwoAnotherThing.

Method 1: Create a proxy class for each proxy, which will result in several classes.
Method 2: Create several proxy methods in one proxy class. When there are more and more proxy methods, it is easy to cause the amount of code in the proxy class to increase. Larger and there is a risk of duplicate names.

For this dynamic proxy was born:

Use of dynamic proxy:

Let's take a look at the interface of the dynamic proxy first:

  1. Implement the InvocationHandler interface

Let's take a look at the structure of the interface:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable; 
//这个接口只有一个方法 就是invoke方法,也就是说我们只要实现invoke方法就可以了
}

Although this parameter does not need to be passed in, we still need to understand that the first is the instance of the proxy class, the second is the method, and the third is the parameter array of the object.

2. Create a proxy instance through the newProxyInstance method:

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

通过这个方法返回我们代理类的实例, 也就是RealObject的Proxy

返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序

From the parameter point of view, the first parameter is the class loader, the second method is a Class object array interface, and the third parameter is the InvocationHandler we implemented above.

I will not post the source code here. If you are interested, you can track it yourself or check my references below.

Dynamic proxy example:

Following the class of the static proxy above, only the test class and the processing class are written below.

Processing class:

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

public class DynamicProxyHandler implements InvocationHandler {

    private Object realObject;

    Object bind(Object realObject){

        this.realObject=realObject;//给真实对象赋值


        return    Proxy.newProxyInstance(realObject.getClass().getClassLoader(),
                                       realObject.getClass().getInterfaces(),
                                        this);
        //通过Class对象得到该对象的构造器,接口方法数组,传入自己构造后的实例.
        //java.reflect.Proxy方法最后返回的是一个代理实例.
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在这里拓展代理逻辑

        System.out.println("rua!");

        Object result= method.invoke(realObject,args);//方法的调用.
        //这里的invoke调用是java进行调用,proxy对象,方法,和参数数组已经是我们之前传入的被代理类的了.

        return result;
    }
}

Test class:

public class DynamicProxy {

    public static void main(String[] args){


        DynamicProxyHandler pHandler=new DynamicProxyHandler();//创建我们动态代理处理类的对象
        Subject proxy=(Subject)pHandler.bind(new RealObject());//对其进行动态代理的参数绑定然后返回一个代理实例
        proxy.doSomething();//调用    
    }
}

The first time I saw it, I was in a fog. I didn't understand why it was dynamic. The method calls here have nothing to do with the method object and are not called directly.
No matter what interface you define in the Subject, it is related to the call . It doesn't matter, rely on reflection, get your method, parameter, class data in real time, and then call it through reflection.

There are ten different RealObjects, and the methods we want to proxy are different, such as the proxy methods: doSomething, doAnotherThing, doTwoAnotherThing.
In this example, I pass in 10 different objects, and the objects naturally have their own Implementation, I get the implementation through reflection and build a new object, which will not affect the original object, and then perform a method call operation on the new object. It is also possible to use 100 to 1000 objects.

All the above conditions are based on reflection. If you don't understand reflection clearly, please go back to see reflection. My blog has also written it, and you can also understand it yourself through the Internet.

References:

1.https://blog.csdn.net/wangqyoho/article/details/77584832
2.https://www.zhihu.com/question/20794107/answer/23330381
3.Thinking in java page 592-598

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325259731&siteId=291194637