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