Dynamic Proxy Proxy case

First, we need three classes

  • Implemented interface
  • A class that implements the interface
  • The test class

Interface class

public interface IUserDao {

    void save();
}
Copy the code

A class that implements the interface

Public class UserDao implements IUserDao {@override public void save() {system.out.println ("---- already saved data! -- "); }}Copy the code

The test class

Public class ProxyDemo {public static void main(String[] args) {// Saves the generated proxy class to disk System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); IUserDao target = new UserDao(); // [primitive type class cn.itcast.b_dynamic.userdao] system.out.println (target.getClass()); ClassLoader = target.getClass().getClassLoader(); // To the target object, IUserDao proxyInstance = (IUserDao) proxy.newProxyInstance (loader, target.getClass().getinterfaces (), (Proxy, Method, args1) -> {system.out.println (" method enhanced before execution "); Object result = method.invoke(target, args1); System.out.println(" method enhanced after execution "); return result; }); // Class $Proxy0 dynamically generated proxy object system.out.println (proxyinstance-getClass ()); // The proxy object executes the method proxyinstance.save (); }}Copy the code

How do I save the generated proxy classes

  • Double-click Shift to open global search for IDEA to find ProxyGenerator

  • Then search for GetBooleanAction in the current class

  • Copy the string and add this line to the first line of the main method (different JDK versions may have different strings)
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Copy the code

Generation of proxy classes

  • Gets the class object of the object and the collection of interfaces implemented by the object
  • Create a proxy object and assign h to it. H is of type InvocationHandler and the value is the anonymous inner class you created
  • A proxy object is created from a class object and interface collection
  • Proxy objects inherit from proxies to implement the interface of the proxied object

The class file of the proxy object

  • Method the object
    • Methods implemented from parent classes and interfaces
  • Static code block
    • Assign to the Method object
  • Rewriting method

Idea decompiled proxy class

package com.sun.proxy; import com.proxy.IUserDao; 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 IUserDao { private static Method m1; private static Method m3; private static Method m2; private static Method m0; static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.proxy.IUserDao").getMethod("save"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void save() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); }}}Copy the code

The method execution flow of the proxy object

  • Any method of the proxy object is executed
// The method that executes is the anonymous inner class of InvocationHandler that we passed in super.h.invoke(this, methodObject, args); (proxy, method, args1) -> {system.out.println (" method enhanced before execution "); Object result = method.invoke(target, args1); System.out.println(" method enhanced after execution "); return result; } // We can control which methods need to be enhanced by proxy, method, Args1) -> {if (" save".equal(method.getName ())) {system.out.println (" enhanced before method execution "); args1) -> {if (" save".equal(method.getName ())) {system.out.println (" enhanced before method execution "); Object result = method.invoke(target, args1); System.out.println(" method enhanced after execution "); return result; }}Copy the code

About memory overflow caused by dynamic proxy

Because dynamic proxies generate CLSS objects of a proxy class and store them in the metadata area, the metadata area can overflow when there are too many dynamic proxy classes.