Static agent

package proxy.statical;

import proxy.Coder;
import proxy.Person;

public class RobotProxy implements Person {

    private Coder coder;

    public RobotProxy(Coder coder) {
        this.coder = coder;
    }

    @Override
    public void cleaning(a) {
        System.out.println("Robot Cleaning Preparation");
        coder.cleaning();
        System.out.println("Robot cleaning Done");
    }

    @Override
    public void cooking(a) {
        System.out.println("Robot Cooking Ready");
        coder.cooking();
        System.out.println("Robot finished cooking."); }}Copy the code

test

package proxy.statical;

import proxy.Coder;

public class StaticalTest {

    public static void main(String[] args) {
        RobotProxy robotProxy = new RobotProxy(newCoder()); robotProxy.cleaning(); robotProxy.cooking(); }}Copy the code

A dynamic proxy

jdk

package proxy.dynamic.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKProxy implements InvocationHandler {

    private Object target;

    public Object getJDKProxy(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK dynamic Proxy, go");
        Object invoke = method.invoke(target, args);
        System.out.println("JDK dynamic proxy, end");
        returninvoke; }}Copy the code
package proxy.dynamic.jdk;

import proxy.Coder;
import proxy.Person;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;

public class JdkProxyTest {

    public static void main(String[] args) {
        JDKProxy jdkProxy = new JDKProxy();
        Person person = (Person) jdkProxy.getJDKProxy(new Coder());
        person.cleaning();
        person.cooking();

        viewSourceCode();
    }

    /** * View dynamic proxy dynamically generated code */
    public static void viewSourceCode(a) {
        byte[] proxyClass = ProxyGenerator.generateProxyClass("$Proxy0".new Class[]{Person.class});
        try {
            FileOutputStream fos = new FileOutputStream("E://$Proxy.class");
            fos.write(proxyClass);
        } catch(IOException e) { e.printStackTrace(); }}}Copy the code

cglib

I need to import two packages

  • Asm 7.2. The jar
  • Additional – 3.3.0. Jar
package proxy.dynamic.cglib;

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 CglibProxy implements MethodInterceptor {

    private Object target;

    public Object getCglibProxy(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        // Set the parent class. Cglib generates a subclass for the specified class, so you need to specify the parent class
        enhancer.setSuperclass(target.getClass());
        // Set the callback
        enhancer.setCallback(this);
        // Create and return the proxy object
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib dynamic proxy, go.");
        Object invoke = method.invoke(target, objects);
        System.out.println("Cglib dynamic proxy, end.");
        returninvoke; }}Copy the code

test

package proxy.dynamic.cglib;

import proxy.Coder;
import proxy.Person;

public class CglibProxyTest {

    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        Person person = (Person) cglibProxy.getCglibProxy(newCoder()); person.cleaning(); person.cleaning(); }}Copy the code

Handwritten implementation of JDK dynamic proxy

package proxy.custom;

import proxy.custom.source.MyClassLoader;
import proxy.custom.source.MyInvocationHandler;
import proxy.custom.source.MyProxy;

import java.lang.reflect.Method;

public class CustomProxy implements MyInvocationHandler {

    private Object target;

    public Object getCustomProxy(Object target) {
        this.target = target;
        return MyProxy.newProxyInstance(new MyClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
        System.out.println("JDK dynamic Proxy, go");
        Object invoke = method.invoke(target, args);
        System.out.println("JDK dynamic proxy, end");
        returninvoke; }}Copy the code
package proxy.custom.source;

import java.lang.reflect.Method;

public interface MyInvocationHandler {

    Object invoke(Object invoke, Method method, Object[] args) throws Exception;

}
Copy the code
package proxy.custom.source;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class MyClassLoader extends ClassLoader {

    private File classPathFile;

    public MyClassLoader(a) {
        String classPath = MyClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }

    @Override
    publicClass<? > findClass(String name)throws ClassNotFoundException {
// String className = MyClassLoader.class.getPackage().getName() + "." + name;
        // proxy/custom/source/$Proxy0 (wrong name: proxy/custom/$Proxy0)
        // The class file is generated under proxy/custom/source/.
        String className = "proxy/custom/$Proxy0";
        if(classPathFile ! =null) {
            File classfile = new File(classPathFile, name.replaceAll("\ \."."/") + ".class");
            if (classfile.exists()) {
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classfile);
                    out = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while((len = in.read(buff)) ! = -1) {
                        out.write(buff, 0, len);
                    }
                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (null! = in) {try {
                            in.close();
                        } catch(IOException e) { e.printStackTrace(); }}if (null! = out) {try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null; }}Copy the code
package proxy.custom.source;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class MyProxy {

    public static final String LN = "\r\n";

    Java Proxy class generates a new class, and the new class implements all the interfaces implemented by the Proxy class. This process is called bytecode reassembly. The JDK has a specification that automatically generates */ whenever the European $starts with */
    public static Object newProxyInstance(MyClassLoader classLoader, Class
       [] interfaces, MyInvocationHandler h) {
        try {
            // 1, generate source code dynamically. Java file
            String src = generateSrc(interfaces);
            // 2, Java file output disk
            String path = MyProxy.class.getResource("").getPath();
            File f = new File(path + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();
            // 3. Compile the generated.java file into a.class file
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null.null.null);
            Iterable<? extends JavaFileObject> iterable = manager.getJavaFileObjects(f);
            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null.null.null, iterable);
            task.call();
            manager.close();
            // 4. The compiled. Class file is loaded into the JVMClass<? > proxyClass = classLoader.findClass("$Proxy0"); Constructor<? > constructor = proxyClass.getConstructor(MyInvocationHandler.class); f.delete();Return the new proxy object after the bytecode reorganization
            return constructor.newInstance(h);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private static String generateSrc(Class
       [] interfaces) {
        StringBuffer sb = new StringBuffer();
        sb.append("package proxy.custom;" + LN);
        sb.append("import proxy.Person;" + LN);
        sb.append("import proxy.custom.source.MyInvocationHandler;" + LN);
        sb.append("import java.lang.reflect.Method;" + LN);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + LN);
        sb.append("MyInvocationHandler h;" + LN);
        sb.append("public $Proxy0(MyInvocationHandler h) { " + LN);
        sb.append("this.h = h;");
        sb.append("}" + LN);
        for (Method m : interfaces[0].getMethods()) {
            sb.append("public " + m.getReturnType().getName() + "" + m.getName() + "() {" + LN);
            sb.append("try {" + LN);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\", new Class[]{});" + LN);
            sb.append("this.h.invoke(this, m, null);" + LN);
            sb.append("} catch (Throwable e) {" + LN);
            sb.append("e.printStackTrace();" + LN);
            sb.append("}" + LN);
            sb.append("}" + LN);
        }
        sb.append("}" + LN);
        returnsb.toString(); }}Copy the code

test

package proxy.custom;

import proxy.Coder;
import proxy.Person;
import proxy.custom.source.MyClassLoader;

public class CustomProxyTest {

    public static void main(String[] args) throws ClassNotFoundException {
        CustomProxy customProxy = new CustomProxy();
        Person person = (Person) customProxy.getCustomProxy(new Coder());
        person.cleaning();
        person.cooking();
// test();
    }

    public static void test(a) throws ClassNotFoundException {
        MyClassLoader myClassLoader = new MyClassLoader();
// System.out.println(myClassLoader.findClass("MyProxy"));
        System.out.println(myClassLoader.findClass("$Proxy0")); }}Copy the code

Common interfaces and classes

package proxy;

public interface Person {

    void cleaning(a);

    void cooking(a);

}
Copy the code
package proxy;

public class Coder implements Person {

    @Override
    public void cleaning(a) {
        System.out.println("cleaning");
    }

    @Override
    public void cooking(a) {
        System.out.println("cooking"); }}Copy the code