Probably every java developer will sooner or later need to use proxy classes.
Under the cut are simple examples made using the JDK proxy, cglib, javassist and byte buddy.
We set ourselves the most simple task:
public class User implements IUser { private final String name; public User() { this(null); } public User(String name) { this.name = name; } @Override public String getName() { return name; } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy;
User user = new User(""); InvocationHandler handler = (proxy, method, args) -> { if(method.getName().equals("getName")){ return ((String)method.invoke(user, args)).toUpperCase(); } return method.invoke(user, args); }; IUser userProxy = (IUser) Proxy.newProxyInstance(user.getClass().getClassLoader(), User.class.getInterfaces(), handler); assertEquals("", userProxy.getName());
The disadvantage is that we can create a proxy class only that implements the interfaces of the class User. Ie you can not cast a proxy class in User
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor;
User user = new User(""); MethodInterceptor handler = (obj, method , args, proxy) -> { if(method.getName().equals("getName")){ return ((String)proxy.invoke(user, args)).toUpperCase() ; } return proxy.invoke(user, args); }; User userProxy = (User) Enhancer.create(User.class, handler); assertEquals("", userProxy.getName());
import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; import javassist.util.proxy.ProxyObject;
User user = new User(""); MethodHandler handler = (self, overridden, forwarder, args) -> { if(overridden.getName().equals("getName")){ return ((String)overridden.invoke(user, args)).toUpperCase(); } return overridden.invoke(user, args); }; ProxyFactory factory = new ProxyFactory(); factory.setSuperclass(User.class); Object instance = factory.createClass().newInstance(); ((ProxyObject) instance).setHandler(handler); User userProxy = (User) instance; assertEquals("", userProxy.getName());
import net.bytebuddy.ByteBuddy; import net.bytebuddy.implementation.MethodDelegation; import static net.bytebuddy.matcher.ElementMatchers.named;
User user = new User(""); User userProxy = new ByteBuddy() .subclass(User.class) .method(named("getName")) .intercept(MethodDelegation.to(new MyInterceptor(user))) .make() .load(User.class.getClassLoader()) .getLoaded() .newInstance(); assertEquals("", userProxy.getName());
public class MyInterceptor { User user; public MyInterceptor(User user) { this.user = user; } public String getName() { return user.getName().toUpperCase(); } }
Productivity, simplicity, modernity - choose for yourself what suits your project more.
For performance comparison, I propose to read the article.
Testing the performance of 4 Java runtime code generators: cglib, javassist, JDK proxy & Byte Buddy
Source: https://habr.com/ru/post/348906/
All Articles