This article does not cover concepts, but mainly code implementation.
Static Proxy
At the JVM level, a static proxy compiles an actual class file with interfaces, implementation classes, and proxy classes.
1. Define the interface for sending text messages
// Define an interface that must be implemented public interface SmsService { String send(String message); }
2. Implement the interface for sending SMS
public class SmsServiceImpl implements SmsService { public String send(String message) { System.out.println("send message:" + message); return message; } }
3. Create a proxy class and also implement the interface for sending SMS
public class SmsProxy implements SmsService { private final SmsService smsService; public SmsProxy(SmsService smsService) { this.smsService = smsService; } @Override public String send(String message) { //We can add our own actions before calling the method System.out.println("before method send()"); smsService.send(message); //After invoking the method, we can also add our own actions System.out.println("after method send()"); return null; } }
4. Actual use
public class Main { public static void main(String[] args) { SmsService smsService = new SmsServiceImpl(); SmsProxy smsProxy = new SmsProxy(smsService); smsProxy.send("java"); } }
After running the above code, the console prints out:
before method send() send message:java after method send()
As you can see from the output, we have added the send() method of SmsServiceImpl.
The static proxy will be able to get file information about the class of the proxy class at compile time. Not flexible enough. Dynamic proxy is generally used.
Dynamic Proxy
From a JVM perspective, a dynamic proxy dynamically generates class byte codes at run time and loads them into the JVM. For Java, there are many ways to implement dynamic proxies, such as JDK dynamic proxy, CGLIB dynamic proxy (we don't need to implement interfaces, we can directly proxy implementation classes) and so on.
- jdk dynamic 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(), // Incoming ClassLoader new Class[] { Hello.class }, // Incoming interfaces to implement handler); // InvocationHandler of the incoming processing call method hello.morning("Bob"); } } interface Hello { void morning(String name); }
Dynamic proxy is actually the process by which the JVM dynamically creates and loads class bytecodes at runtime, rewriting the dynamic proxy above to a static implementation class is roughly as long:
// This class is the proxy class generated above, and when the proxy class method is called, the method in InvocationHandler inside the proxy class is called. If you want to // What to add before and after the method is in the invoke method of the class that implements the InvocationHandler interface. public class HelloDynamicProxy implements Hello { // This is the class above that implements the InvocationHandler interface 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 }); } }
- cglib dynamic proxy
CGLIB(Code Generation Library) is an ASM-based byte code generation library that allows us to modify and dynamically generate byte codes at runtime. CGLIB implements proxy through inheritance. Many well-known open source frameworks use CGLIB, such as the AOP module in Spring: if the target object implements an interface, the JDK dynamic proxy is used by default, otherwise the CGLIB dynamic proxy is used.
AOP is based on the above two.