Appearance
Dynamic Proxy
Let’s compare the differences between Java class
and interface
:
- Can instantiate
class
(nonabstract
); - Cannot instantiate
interface
.
All interface
type variables are always upcast through an instance and assigned to interface type variables:
java
CharSequence cs = new StringBuilder();
Is it possible to create an instance
of an interface directly at runtime without writing an implementation class?
This is possible because the Java standard library provides a dynamic proxy (Dynamic Proxy) mechanism: an instance of an interface
can be dynamically created during runtime.
What is runtime dynamic creation? It sounds complicated. The so-called dynamic proxy corresponds to static. Let’s see how to write static code:
Define interface:
java
public interface Hello {
void morning(String name);
}
Write implementation class:
java
public class HelloWorld implements Hello {
public void morning(String name) {
System.out.println("Good morning, " + name);
}
}
Create an instance, convert it to an interface and call:
java
Hello hello = new HelloWorld();
hello.morning("Bob");
This way is how we usually write code.
Another way is dynamic code. We still define the interface Hello
first, but we do not write an implementation class. Instead, we create a Hello
interface object directly through a Proxy.newProxyInstance()
provided by the JDK. This method that does not implement a class but dynamically creates an interface object during runtime is called dynamic code. The method provided by JDK to dynamically create interface objects is called dynamic proxy.
One of the simplest dynamic proxy implementations is as follows:
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method);
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args[0]);
}
return null;
}
};
Hello hello = (Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(), // Pass in ClassLoader
new Class[] { Hello.class }, // Pass in the interface to be implemented
handler); // Pass in the InvocationHandler that handles the calling method
hello.morning("Bob");
}
}
interface Hello {
void morning(String name);
}
The method to dynamically create an interface
instance at runtime is as follows:
- Define an
InvocationHandler
instance, which is responsible for implementing the method invocation of the interface; - Create an
interface
instance throughProxy.newProxyInstance()
, which requires 3 parameters:ClassLoader
used is usuallyClassLoader
of the interface class;- The array of interfaces that need to be implemented requires at least one interface to be passed in;
InvocationHandler
instance used to handle interface method calls.
- Cast the returned
Object
into an interface.
Dynamic proxy is actually a process in which the JVM dynamically creates class bytecode and loads it during runtime. There is no black magic in it. Rewriting the above dynamic proxy into a static implementation class probably looks like this:
java
public class HelloDynamicProxy implements Hello {
InvocationHandler handler;
public HelloDynamicProxy(InvocationHandler handler) {
this.handler = handler;
}
public void morning(String name) {
handler.invoke(
this,
Hello.class.getMethod("morning", String.class),
new Object[] { name }
);
}
}
In fact, the JVM automatically writes the above class for us (no source code is required, bytecode can be directly generated), and there is no black magic that can directly instantiate the interface.
Summary
The Java standard library provides a dynamic proxy function, allowing an instance of an interface to be dynamically created during runtime;
Dynamic proxy is accomplished by creating a proxy object through Proxy
, and then "proxying" the interface method to InvocationHandler
.