AOP Implementation Using CGLIB Subclass Proxies
Core Concepts of Aspect-Oriented Programming
Aspect-Oriented Programming (AOP) extracts cross-cutting concerns from business logic. It targets specific steps or phases in a process, achieving low coupling between logical components.
A proxy acts as a surrogate or placeholder, controlling access to another object. It allows adding extra behavior before or after the target object's execution, effectively extending its functionality.
CGLIB-Based Subclass Proxies
CGLIB generates proxy objects by creating a subclass of the target class at runtime. This approach overcomes a key limitation of JDK dynamic proxies, which require the target to implement at least one interface. CGLLIB proxies classes directly using bytecode manipulation powered by the ASM framework. Major AOP frameworks such as Spring leevrage it to enable method interception.
Several constraints apply:
- The target class cannot be declared
final. - Methods marked
finalorstaticwill not be intercepted. - Include the CGLIB library; Spring's core module packages it, so adding
spring-coreis sufficient.
Implementation Example
Consider a plain service class that acts as the intercept target:
package com.example.aop.cglib;
public class AccountService {
public void processTransaction() {
System.out.println("Processing transaction...");
}
}
Define a proxy factory that implements Spring's MethodInterceptor:
package com.example.aop.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/*
* Subclass proxy factory using CGLIB.
* Intercepts method calls to add behavior.
*/
public class ServiceProxyInterceptor implements MethodInterceptor {
private final Object delegate;
public ServiceProxyInterceptor(Object delegate) {
this.delegate = delegate;
}
/*
* Creates a dynamically generated subclass proxy instance.
*/
public Object createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(delegate.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object enhancedInstance, Method method, Object[] arguments,
MethodProxy methodProxy) throws Throwable {
System.out.println(">>> Interception start");
Object result = methodProxy.invokeSuper(enhancedInstance, arguments);
System.out.println("<<< Interception end");
return result;
}
}
After execution, the returned reference is no longer the original AccountService but an enhanced CGLIB-generated subclass instance. The console output confirms that the custom logic runs before and after the target method.
Choosing Between JDK and CGLIB Proxies in Spring AOP
Spring's default strategy is straightforward:
- If the target bean implements an interface, the JDK dynamic proxy is used.
- If no interface is implemented, CGLIB subclass proxy is applied automatically.