Going to Ali for an interview? These skills you don't know yet, Java dynamic agent mechanism - those skills that make your interview stand out

foreword

I don't know if you have read this article:

Like Kotlin, Jetpack, modular design these are the hottest technologies this year, why don't I talk about it? Because there are many very powerful big bloggers who must have said it, I will not come here to show ugliness. Today I want to tell you about the problem of Java dynamic proxy mechanism. Why? Because of this epidemic, I also quit my job and stayed at home for a long time. Hasn't the epidemic improved recently? I went to interview, ByteDance, Tencent. . . I found out that they ask the following questions when interviewing. So today I will take it out and tell you about it, I hope you can gain something!

Start

Retrofit is a network request framework with high decoupling. Recently, I discovered dynamic proxy, a very powerful and practical technology during research. This article will be used as the prerequisite knowledge of retrofit to let everyone know: What are the applications of dynamic proxy? Scenario, what is dynamic proxy, how to use it, and what are its limitations? #Application scenarios of dynamic proxy

1. AOP - Aspect-oriented programming, program decoupling In short, when you want to do some common operations before and after execution of some methods inside some classes, and perform personalized operations in the methods – Use dynamic proxies. When the business volume is huge, the amount of code can be reduced and the maintainability can be enhanced.

2. I want to customize some methods in the third-party class library. I refer to a third-party class library, but some of its methods do not meet my needs. I want to rewrite those methods myself, or before and after the method. Add some special operations - use dynamic proxies. But it's important to note that these methods have limitations, which I'll explain later.

What is a dynamic proxy

The above diagram is too abstract, so let's start with examples in life.

If you are a big landlord (agent), you have a lot of houses you want to rent out, but you feel that it is too troublesome to find tenants and do not want to do it yourself, so you find someone to represent you (agent) Take care of these things, and this person (the agent is the intermediary) will charge you some corresponding intermediary fees when you rent out the house (some additional operations for the rental of the house). For the tenant, the agent is the landlord who does something on your behalf.

The above is an example of an agent, and why is it called a dynamic agent, where are the two "dynamic" fonts now?

We can think of it this way, if you hire an agent to help you take care of each house, and every time you want to rent out another house, you have to hire another one, so you will hire a lot of agents and spend High intermediary costs, which can be seen as the so-called "static proxy".

But if we hand over all the houses to an agent, let him dynamically switch between multiple houses to help you deal with each tenant. This is a "dynamic proxy" process. A major feature of dynamic proxy is that there is no proxy class in the compilation phase, and the proxy class is generated at runtime.

Let's take a look at a piece of code

The operation of housing rental

/**
*定义一个借口
**/
public interface RentHouse {
void rent();//房屋出租
void charge(String str);//出租费用收取
}

landlord

public class HouseOwner implements RentHouse {
public void rent() {
    System.out.println("I want to rent my house");
}

public void charge(String str) {
    System.out.println("You get : " + str + " RMB HouseCharge.");
}
}

intermediary

public class DynamicProxy implements InvocationHandler {

// 这个就是我们要代理的真实对象,即房东
private Object subject;

//  构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Object subject) {
    this.subject = subject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //  在代理真实对象前我们可以添加一些自己的操作,中介收取中介费
    System.out.println("before "+method.getName()+" house");

    System.out.println("Method:" + method.getName());

    //        如果方法是 charge 则中介收取100元中介费
    if (method.getName().equals("charge")) {

        method.invoke(subject, args);
        System.out.println("I will get 100 RMB ProxyCharge.");

    } else {
        //    当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(subject, args);
    }

    //  在代理真实对象后我们也可以添加一些自己的操作
    System.out.println("after "+method.getName()+" house");

    return null;
}

guest

public class Client {
public static void main(String[] args)
{
    //    我们要代理的真实对象--房东
    HouseOwner houseOwner = new HouseOwner();

    //    我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
    InvocationHandler handler = new DynamicProxy(houseOwner);

    /*
     * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
     * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
     * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
     * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
     */
    RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner
            .getClass().getInterfaces(), handler);//一个动态代理类,中介

    System.out.println(rentHouse.getClass().getName());
    rentHouse.rent();
    rentHouse.charge("10000");
}
}

Let's look at the output

com.sun.proxy.$Proxy0
before rent house
Method:rent
I want to rent my house
after rent house
before charge house
Method:charge
You get : 10000 RMB HouseCharge.
I will get 100 RMB ProxyCharge.
after charge house

Process finished with exit code 0

The output has before rent house and after rent house, indicating that we can add operations before and after the method. Look at the output I will get 100 RMB ProxyCharge. The intermediary charged a fee of 100 yuan, which means that we can not only increase the operation, but also replace the method or directly let the method not execute.

You may have a lot of doubts when you first look at the code. Let's take a look at how dynamic proxy should be used through the following content.

#How to use dynamic proxy In the dynamic proxy mechanism of java, there are two important classes and interfaces, one is InvocationHandler(Interface), and the other is Proxy(Class). This class and interface are used to implement our dynamic proxy. must be used.

Each dynamic proxy class must implement the InvocationHandler interface (intermediary in the code), and each proxy class instance is associated with a handler. When we call a method through the proxy object, the method call will be called by Forwarding is called by the invoke method of the InvocationHandler interface (the enhancement of the method is written here).

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

We see that this method accepts a total of three parameters, so what do these three parameters represent?

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
//proxy:  指代我们所代理的那个真实对象
//method:  指代的是我们所要调用真实对象的某个方法的Method对象
//args:  指代的是调用真实对象某个方法时接受的参数

Next, let's take a look at the Proxy class

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

The role of the Proxy class is to dynamically create a class of proxy objects. It provides many methods, but the one we use the most is the newProxyInstance method:

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

The function of this method is to get a dynamic proxy object that receives three parameters. Let's take a look at the meanings of these three parameters.

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

//loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
//interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
//h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

In this way, combined with the code given above, we can understand the use of dynamic proxy

Limitations of dynamic proxy From the use of dynamic proxy, we can see that the methods that can be enhanced are all implemented with excuses (public methods that do not implement excuses can also be used by inheriting the proxied class), HouseOwner in the code inherits RentHouse. And for the dynamic proxy of the private method JDK can do nothing! The above dynamic agents are from JDK. There is also the famous CGLib for java projects. Unfortunately, CGLib cannot be used in android. The android virtual machine is relatively different from the jvm.

concluding remarks

The usage scenarios of dynamic proxies are far more than these. The internal principles will be introduced in future articles, but the mechanism of applying class reflection to temporarily generate proxy classes determines that it will have a certain impact on performance. This article is not too detailed as a pre-article of the retrofit principle. If there are any omissions and mistakes, please correct me!

Other interview materials and analysis

If you need it, you can **click【Android Senior Engineer Advanced Learning】** to join our circle and learn and communicate with us! Just skip it if you don't need it!


Android Advanced Learning Complete Manual

Android benchmarking Ali P7 learning video

BATJ factory Android high-frequency interview questions

Related Posts