A demo,

Tom finds an agent to rent a house

  • 1. First, define an interface HouseRenting class that represents the common behavior of renting
public interface HouseRenting {
    void rent();
}
Copy the code
    1. Tom, the agent class, represents the behavior to be implemented, Tom is going to rent the house
public class Tom implements HouseRenting { @Override public void rent() { System.out.println("Tom want to rent a house"); }}Copy the code
  • 3. Proxy class JDKProxyHandler
public class JDKProxyHandler implements InvocationHandler { private Object object; public JDKProxyHandler(Object object){ this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//before system.out.println (" take Tom to see the house - arrive at the specified place "); Object invoke = method.invoke(object, args); //after system.out.println (" take Tom to see the room - sign the contract "); return invoke; } public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), this); }}Copy the code
  • 4. Test method
public class Main { public static void main(String[] args) { Tom tom = new Tom(); JDKProxyHandler handler = new JDKProxyHandler(tom); HouseRenting proxy = (HouseRenting) handler.getProxy(); proxy.rent(); }}Copy the code
  • 5. Output the result
Tom: I want to rent a house before I arrive at the appointed placeCopy the code

Two, look at the source code

  • Generate the $proxy0.class method
public class JdkProxySourceClass { public static void main(String[] args) { byte[] classFile = ProxyGenerator.generateProxyClass("$proxy0", new Class[]{HouseRenting.class}); FileOutputStream fos = null; try { fos = new FileOutputStream("/Users/test/$Proxy0.class"); fos.write(classFile); fos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fos ! = null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }Copy the code
    1. $proxy0.class part of the code
public final class $proxy0 extends Proxy implements HouseRenting { private static Method m3; $proxy0(invocationHandler var1) throws {super(var1); $proxy0(invocationHandler var1) throws {super(var1); } // Invoke () method of InvocationHandler public final void rent() throws {try {super.h. ivoke (this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); Static}} {the try {/ / static block of code creates the proxy Class methods m3 = Class. Class.forname (" proxy. Staticproxy. HouseRenting "). GetMethod (" rent "); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); }}}Copy the code
    1. Java dynamic proxy implementation principles
public static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h) throws IllegalArgumentException { /* * Look up or generate the designated proxy class. Class com.sun.proxy.$Proxy0 */ class <? > cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated Invocation handler. public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler) */ try { final Constructor<? > cons = cl.getConstructor(constructorParams); Return cons.newInstance(new Object[]{h});Copy the code
  • 9. The getProxyClass0 method creates the class through the interface
private static Class<? > getProxyClass0(ClassLoader loader, Class<? >... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); }Copy the code
    1. The cached value of proxyClassCache. Get from the previous step will eventually be retrieved from a call to ProxyClassFactory#apply
{ Map<Class<? >, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<? > intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<? > interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); }}}Copy the code

Can be found and used to generate the proxy class bytecode code is: ProxyGenerator. GenerateProxyClass, then call native defineClass0 load bytecode generation class object.