JAVA static proxy and JDK dynamic proxy

preface

This article will briefly introduce the static proxy of java and the dynamic proxy of JDK.
Recently, I was studying JAVA related knowledge and found that the relevant explanations of agents on the Internet are too messy, so I sort them out here for reference.
I have little engineering experience, so I don't know why to use the agent mode. This paper mainly expounds how to use dynamic and static agents.

Static proxy

Suppose there is an interface Interface1, which specifies that there must be two functions void fun1() and void fun2() to implement this interface

interface Interface1
{
	void fun1();
	int fun2();
}

Suppose there is another implementation of this interface

class MyClass1 implements Interface1
{
	public MyClass1(){}
	public void fun1()//Implement fun1
	{
		System.out.println("run fun1");
	}
	public int fun2()//Realize fun2
	{
		System.out.println("run fun2");
		return 1;
	}
}

Suddenly one day, we want to add some operations before (after) implementing the method of the interface. Our first thought is to design a subclass of the class that implements the interface.

class MyChildClass extends MyClass1
{
	public MyChildClass(){super();}
	
    private void doSomethingBefore(){
        System.out.println("do something before");
    }
    private void doSomethingAfter(){
        System.out.println("do something after");
    }
    
    //Heavy duty fun1
    @Override
    public void fun1() {
        doSomethingBefore();//Do some operations before executing the parent class fun1
        super.fun1();
        doSomethingAfter();//Perform some operations after executing the parent class fun1
    }
	
	//Heavy duty fun2
    @Override
    public int fun2() {
        doSomethingBefore();
        int tmp_res = super.fun2();
        doSomethingAfter();
        return tmp_res;
    }
}

This is static overloading, that is, inheriting the original class for some operations

package com.company.zz
import java.util.*;
public class zz{
	public static void main(String[] args)
	{
		MyChildClass mcc1 = new MyChildClass();
		mcc1.fun1();
		mcc2.fun2();
	}
}

The output of the above code is:

do something before
run fun1
do something after
do something before
run fun2
do something after

JDK dynamic agent

In the above example, the interface has only two methods. However, if there are many methods, the static proxy is very troublesome. In this case, you can use dynamic proxy.

import java.lang.reflect.InvocationHandler;

class MC1Handler implements InvocationHandler//JDK dynamic proxy must implement interface InvocationHandler
{
    private Object tar;//tar is used to store the proxy instance
    MC1Handler(Object tar){
        this.tar = tar;
    }
    
	//Create proxy
    public Interface1 createProxyObj(){
        return (Interface1)Proxy.newProxyInstance(
	        this.tar.getClass().getClassLoader(), 
	        this.tar.getClass().getInterfaces(),
	        this);
    }
    
	//When calling the method in the interface of the proxy instance, the invoke method will be called automatically
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        System.out.println("the ProxyHandler is Invoked.");
        doSomethingBefore();
        Object res = method.invoke(this.tar,args);
        doSomethingAfter();
        return res;
    }
    
    private void doSomethingBefore(){
        System.out.println("do something before");
    }
    private void doSomethingAfter(){
        System.out.println("do something after");
    }
}

package com.company.zz
import java.util.*;
public class zz{
	public static void main(String[] args)
	{
		
		MyClass1 mc1Ins1 = new MyClass1();
        MC1Handler mc1hander = new MC1Handler(mc1Ins1);//Create an instance of the proxy class
        Interface1 mc1Han = mc1hander.createProxyObj();//Get agent
        mc1Han.fun1();//Call fun1
        mc1Han.fun2();//Call fun2
	}
}

The output result is

the ProxyHandler is Invoked.
do something before
run fun1
do something after
We will call fun2
the ProxyHandler is Invoked.
do something before
run fun2
do something after

It can be found that when we call fun1() and fun2() through a proxy, they actually call invoke (object proxy, method, object [] args) in the proxy class.

In addition, we found that in Above code Line 8 of.

Interface1 mc1Han = mc1hander.createProxyObj();//Get agent

The proxy we will get is the type of interface Interface1, not the type of class MyClass1 of the proxy instance. Therefore, if there is a method in the class that is not in interface Interface1, it will not be proxied. Namely:

class MyClass1 implements Interface1{
	MyClass1(){};
	void fun1(){/*do something*/}//Implement methods in the interface
	int fun2(){/*do something*/}//Implement methods in the interface
	void fun3(){/*do something*/}//MyClass1's own method is not a method in the interface
}

When acting as a proxy for this class, fun3 cannot be called through the proxy because there is no such method in the interface.

package com.company.zz
import java.util.*;
public class zz{
	public static void main(String[] args)
	{
		
		MyClass1 mc1Ins1 = new MyClass1();
        MC1Handler mc1hander = new MC1Handler(mc1Ins1);//Create an instance of the proxy class
        Interface1 mc1Han = mc1hander.createProxyObj();//Get agent
        mc1Han.fun1();//Call fun1
        mc1Han.fun2();//Call fun2
        
//        mc1Han.fun3();//Error!  Fun3 is not callable, it is not a method in the interface
	}
}

It can be found that when using static proxy, you can formulate your own processing function for each method. However, when using dynamic proxy, when calling different methods, the invoke method in the proxy class is called. If you want to perform different processing for different methods, you can use reflection.

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
    	if(method.getName() == "fun1")//Need to import Java lang.reflect. Method;
    	{
			//do something for fun1()
		}
		else if(method.getName() == "fun2")//Need to import Java lang.reflect. Method;
    	{
			//do something for fun2()
		}
		else
		{
			//do something for others
		}
        Object res = method.invoke(this.tar,args);
        return res;
    }

Keywords: Java reflection

Added by rsmarsha on Fri, 18 Feb 2022 10:18:03 +0200