Creating a Proxy Object Using cglib
A Java-based proxy object can be utilized when you need a method invocation handler. Here's a look at creating a proxy object with cglib, a super useful Java bytecode generation library.
Join the DZone community and get the full member experience.
Join For FreeIn the previous post I was talking about the standard Java-based proxy objects. These can be used when you want to have a method invocation handler on an object that implements an interface. The Java reflection proxy creation demands that you have an object that implements the interface. The object we want to proxy is out of our hand, it does not implement the interface that we want to invoke from our handler, and still we want to have a proxy.
When Do We Need Proxy to Objects Without Interface?
This is a very common case. If ever we have a JPA implementation e.g. Hibernate that implements lazy loading of the records. For example, the audit log records are stored in a table and each record, except the first one, has a reference to the previous item. Something like
class LinkedAuditLogRecord {
LinkedAuditLogRecord previous;
AuditLogRecord actualRecord;
}
Loading a record via JPA will return an object LinkedAuditLogRecord which contains the previous record as an object and so on until the first one that probably has null in the field named previous. (This is not an actual code.) Any JPA implementation grabbing and loading the whole table from the start to the record of our interest would be an extremely poor implementation. Instead the persistence layer loads the actual record only and creates a proxy object extending LinkedAuditLogRecord and that is what the field previous is going to be. The actual fields are usually private fields and if ever our code tries to access the previous record the proxy object will load it that time. This is lazy loading in short.
But how do the JPA implementations create proxies to objects of classes that do not implement interfaces? Java reflection proxy implementation can not do that and thus JPA implementation uses something different. What they usually use is cglib.
What is cglib
Cglib is an open source library that capable creating and loading class files in memory during Java runtime. To do that it uses Java bytecode generation library ‘asm’, which is a very low-level bytecode creation tool. I will not dig that deep in this article.
How to Use cglib
To create a proxy object using cglib is almost as simple as using the JDK reflection proxy API. I created the same code as the last week article, this time using cglib:
package proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyDemo {
static class Original {
public void originalMethod(String s) {
System.out.println(s);
}
}
static class Handler implements MethodInterceptor {
private final Original original;
public Handler(Original original) {
this.original = original;
}
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("BEFORE");
method.invoke(original, args);
System.out.println("AFTER");
return null;
}
}
public static void main(String[] args){
Original original = new Original();
MethodInterceptor handler = new Handler(original);
Original f = (Original) Enhancer.create(Original.class,handler);
f.originalMethod("Hallo");
}
}
The difference is that name of the classes are a bit different and we do not have an interface.
It is also important that the proxy class extends the original class and thus when the proxy object is created it invokes the constructor of the original class. In case this is resource hungry we may have some issue with that. However this is something that we can not circumvent. If we want to have a proxy object to an already existing class then we should have either an interface or we have to extend the original class, otherwise we just could not use the proxy object in place of the original one.
Published at DZone with permission of Peter Verhas, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments