English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Static proxy pattern
Proxy pattern can be used when it is necessary to process some functions twice or when certain functions should not be known to the outside world. By accessing a third party to indirectly access the original function, the above purpose can be achieved.
interface Hosee{ String sayhi(); class Hoseeimpl implements Hosee{ @Override public String sayhi() return "Welcome oschina hosee's blog"; class HoseeProxy implements Hosee{ Hosee h; public HoseeProxy(Hosee h) this.h = h; @Override public String sayhi() System.out.println("I'm proxy!"); return h.sayhi(); public class StaticProxy public static void main(String[] args) Hoseeimpl h = new Hoseeimpl(); HoseeProxy hp = new HoseeProxy(h); System.out.println(hp.sayhi());
1.1 The disadvantages of static proxy
If you want to proxy multiple classes, you need to establish multiple proxy classes, which increases the difficulty of maintenance.
Upon careful consideration, why does static proxy have these issues? It is because the proxy is already decided at compile time. If the proxy occurs at runtime, these issues can be resolved more simply, which is why the existence of dynamic proxy is very necessary.
2. dynamic proxy
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface HoseeDynamic String sayhi(); class HoseeDynamicimpl implements HoseeDynamic @Override public String sayhi() return "Welcome oschina hosee's blog"; class MyProxy implements InvocationHandler Object obj; public Object bind(Object obj) this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable System.out.println("I'm proxy!"); Object res = method.invoke(obj, args); return res; public class DynamicProxy public static void main(String[] args) MyProxy myproxy = new MyProxy(); HoseeDynamicimpl dynamicimpl = new HoseeDynamicimpl(); HoseeDynamic proxy = (HoseeDynamic)myproxy.bind(dynamicimpl); System.out.println(proxy.sayhi());
By analogy with static proxy, it can be found that the proxy class does not need to implement the original interface, but implements InvocationHandler. Through
Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this);
To dynamically generate a proxy class, the class loader of which is the same as that of the proxy class, and the implemented interface is the same as that of the proxy class.
The proxy class generated by the above method is equivalent to the proxy class in static proxy.
This achieves the determination of the proxy object at runtime, solving the disadvantages of static proxy.
When the dynamically generated proxy class calls a method, it will trigger the invoke method, in which the method of the proxy class can be enhanced.
Through dynamic proxy, its benefits can be clearly seen. When using static proxy, if some classes with different interfaces want to use the proxy pattern to implement the same function, multiple proxy classes need to be implemented, but in dynamic proxy, only one proxy class is needed.
In addition to reducing the workload of writing proxy classes, dynamic proxy achieves the ability to determine the proxy behavior of the proxy class when the original class and interface are unknown. After the proxy class is disconnected from the original class, it can be reused flexibly in different application scenarios.
2.1 Disadvantages of dynamic proxy
Both the proxy class and the delegate class need to implement the same interface. That is to say, only classes that have implemented an interface can use the Java dynamic proxy mechanism. However, in fact, not all classes encountered in use will implement an interface. Therefore, for classes that do not implement an interface, this mechanism cannot be used.
CGLIB can achieve dynamic proxy for classes
2.2 Principle of callback function
As mentioned above, when the dynamically generated proxy class calls a method, it triggers the invoke method.
Obviously, the invoke method is not explicitly called, it is a callback function, so how is the callback function called?
In the code of the above dynamic proxy, the only unclear place is
Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this);
Tracing the source code of this method, we can see that the program performs operations such as verification, optimization, caching, synchronization, bytecode generation, and class loading. The previous steps are not the focus of our attention, but the last it calls
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);
This method is used to complete the bytecode generation action, which can generate a byte[] array describing the proxy class at runtime.
Add this in the main function:
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
After adding this line of code and running the program again, a class file named ”$Proxy().class” will be generated in the disk, which is a proxy class. (I use JD for decompiling)-After the GUI )you can see the following code:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements HoseeDynamic private static Method m1; private static Method m3; private static Method m0; private static Method m2; public $Proxy0(InvocationHandler paramInvocationHandler) throws super(paramInvocationHandler); public final boolean equals(Object paramObject) throws try return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); catch (Error|RuntimeException localError) throw localError; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable); public final String sayhi() throws try return (String)this.h.invoke(this, m3, null); catch (Error|RuntimeException localError) throw localError; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable); public final int hashCode() throws try return ((Integer)this.h.invoke(this, m0, null)).intValue(); catch (Error|RuntimeException localError) throw localError; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable); public final String toString() throws try return (String)this.h.invoke(this, m2, null); catch (Error|RuntimeException localError) throw localError; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable); static try m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("HoseeDynamic").getMethod("sayhi", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); return; catch (NoSuchMethodException localNoSuchMethodException) throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); catch (ClassNotFoundException localClassNotFoundException) throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
The dynamic proxy class not only proxies the methods defined explicitly in the interface, but also proxies the three methods inherited from the java root class Object, namely equals(), hashcode(), and toString(), and only these three methods.
As can be seen from the above code, regardless of which method is called, it will call the invoke method of InvocationHandler, but the parameters are different.
2.3 Difference between dynamic proxy and static proxy
The code of the Proxy class is fixed and will not become large due to the gradual expansion of the business;
It can implement AOP programming, which is not achievable by static proxy;
Decoupling, if used in web business, it can achieve separation of data layer and business layer.
The advantage of dynamic proxy is to achieve non-intrusive code extension. The static proxy pattern itself has a major problem; when the number of class methods increases, the code volume of the proxy class is very large. Therefore, dynamic proxy is introduced to solve this problem
3. CGLIB
Cglib is designed to implement proxy for classes. Its principle is to generate a subclass for the specified target class and override the methods to achieve enhancement. However, since inheritance is used, proxy cannot be applied to classes with the final modifier.
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; class CGlibHosee public String sayhi() return "Welcome oschina hosee's blog"; class CGlibHoseeProxy Object obj; public Object bind(final Object target) this.obj = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(new MethodInterceptor() @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable System.out.println("I'm proxy!"); Object res = method.invoke(target, args); return res; }); return enhancer.create(); public class CGlibProxy public static void main(String[] args) CGlibHosee cGlibHosee = new CGlibHosee(); CGlibHoseeProxy cGlibHoseeProxy = new CGlibHoseeProxy(); CGlibHosee proxy = (CGlibHosee) cGlibHoseeProxy.bind(cGlibHosee); System.out.println(proxy.sayhi());
cglib needs to specify the superclass and callback method. Of course, cglib can also be used like Java dynamic proxy, which is also an interface-oriented, because the essence is inheritance.
Thank you for reading, I hope it can help everyone, thank you for your support to this site!