Detailed Explanation of Dynamic Proxy Mechanism in Java
I. Concept and Role of Dynamic Proxy
Dynamic proxy is a technique for dynamically creating proxy classes and objects at runtime. It allows you to add additional functionality (such as logging, permission checking, transaction management, etc.) to method calls of an object without modifying the original class code. The core value of dynamic proxy lies in achieving the separation of "cross-cutting concerns."
II. Implementation Methods of Dynamic Proxy
Java provides two main dynamic proxy implementation methods:
-
JDK Dynamic Proxy
- Based on interface implementation, requiring the target class to implement at least one interface.
- Core classes:
java.lang.reflect.Proxyandjava.lang.reflect.InvocationHandler
-
CGLIB Dynamic Proxy
- Based on inheritance implementation, creating a proxy by generating a subclass of the target class.
- Can proxy ordinary classes that do not implement interfaces.
III. Detailed Implementation Steps of JDK Dynamic Proxy
Step 1: Define Business Interface
// User Service Interface
public interface UserService {
void addUser(String username);
void deleteUser(String username);
}
Step 2: Implement Business Interface (Target Class)
// Target Class - Implementation of actual business logic
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("Add user: " + username);
}
@Override
public void deleteUser(String username) {
System.out.println("Delete user: " + username);
}
}
Step 3: Implement the InvocationHandler Interface
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LoggingHandler implements InvocationHandler {
private final Object target; // Target object
public LoggingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Pre-enhancement: Logic before method execution
System.out.println("[Log] Start executing method: " + method.getName());
System.out.println("[Log] Parameters: " + (args != null ? String.join(",", args) : "None"));
long startTime = System.currentTimeMillis();
// Call the original method of the target object
Object result = method.invoke(target, args);
// Post-enhancement: Logic after method execution
long endTime = System.currentTimeMillis();
System.out.println("[Log] Method execution time: " + (endTime - startTime) + "ms");
System.out.println("[Log] Method execution completed");
return result;
}
}
Step 4: Create Proxy Object and Use It
import java.lang.reflect.Proxy;
public class DynamicProxyDemo {
public static void main(String[] args) {
// Create target object
UserService target = new UserServiceImpl();
// Create InvocationHandler instance
InvocationHandler handler = new LoggingHandler(target);
// Create proxy object
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // Class loader
target.getClass().getInterfaces(), // Interface array
handler // Invocation handler
);
// Call methods through proxy object
proxy.addUser("Zhang San");
proxy.deleteUser("Li Si");
}
}
IV. Implementation of CGLIB Dynamic Proxy
Step 1: Add CGLIB Dependency
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
Step 2: Implement the MethodInterceptor Interface
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibLoggingInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("[CGLIB Log] Start executing method: " + method.getName());
long startTime = System.currentTimeMillis();
// Call the parent class (target class) method
Object result = proxy.invokeSuper(obj, args);
long endTime = System.currentTimeMillis();
System.out.println("[CGLIB Log] Method execution time: " + (endTime - startTime) + "ms");
return result;
}
}
Step 3: Create Proxy Object
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
// Set parent class (target class)
enhancer.setSuperclass(UserServiceImpl.class);
// Set callback handler
enhancer.setCallback(new CglibLoggingInterceptor());
// Create proxy object
UserService proxy = (UserService) enhancer.create();
proxy.addUser("Wang Wu");
}
}
V. Comparative Analysis of the Two Dynamic Proxies
| Feature | JDK Dynamic Proxy | CGLIB Dynamic Proxy |
|---|---|---|
| Implementation Basis | Interface-based | Inheritance-based |
| Performance | Calls reflective methods, slower | Directly calls parent class methods, faster |
| Limitations | Must implement an interface | Cannot proxy final classes and methods |
| Dependencies | Native JDK support | Requires additional JAR |
VI. Practical Application Scenarios of Dynamic Proxy
- Spring AOP: The Spring framework uses dynamic proxies to implement aspect-oriented programming.
- MyBatis: Proxy implementation of Mapper interfaces.
- Hibernate: Implementation of lazy loading functionality.
- RPC Framework: Client-side proxy for remote method calls.
- Transaction Management: Foundation for declarative transaction implementation.
VII. In-depth Understanding of Core Principles
The core of dynamic proxy lies in:
- Proxy Class Generation: Dynamically generates the bytecode of the proxy class at runtime through bytecode technology.
- Method Forwarding: All method calls are redirected to the
invokemethod of theInvocationHandler. - Chain of Responsibility Pattern: Implements the combination of multiple enhancement functions through a proxy chain.
Through dynamic proxies, we can achieve a complete separation of business logic and cross-cutting concerns, greatly improving code maintainability and reusability.