代理是什么呢?
代理可以理解为代购,虽然最终结果是你买了商品,但是是代购替你买回来的。
静态代理
// 接口
public interface Shopping {
Object[] doShopping(double money);
}
// 实现类:你买东西
public class ShoppingImpl implements Shopping {
@Override
public Object[] doShopping(double money) {
System.out.println(String.format("花%s块钱买东西。", money));
Object o[] = {"衣服", "手机", "MacBook Pro"};
return o;
}
}
// 静态代理类:代理替你买东西
public class ProxyShopping implements Shopping {
public static void main(String args[]) {
// 其实本质还是你买
Shopping shopping = new ShoppingImpl();
System.out.println(Arrays.toString(new ProxyShopping(shopping).doShopping(6000)));
}
private Shopping shopping;
public ProxyShopping(Shopping shopping) {
this.shopping = shopping;
}
@Override
public Object[] doShopping(double money) {
System.out.println("使用静态代理来购物...");
Object[] o = shopping.doShopping(money);
if (o != null && o.length > 1) {
o[0] = "被掉包的东西!!!";
}
return o;
}
}
动态代理
传统的静态代理需要为每一个被代理的类写一个代理,比较麻烦。所以有了动态代理,动态代理主要是用InvocationHandler
和Proxy
类。
public class ShoppingHandler implements InvocationHandler {
public static void main(String args[]) {
Shopping shopping = new ShoppingImpl();
// 得到代理对象
shopping = (Shopping) Proxy.newProxyInstance
(Shopping.class.getClassLoader(), shopping.getClass().getInterfaces(), new ShoppingHandler(shopping));
System.out.println(Arrays.toString(shopping.doShopping(600)));
}
// 被代理的对象
private Object obj;
public ShoppingHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("doShopping")) {
System.out.println("动态代理:执行操作-可以修改入参");
Object[] ob = (Object[]) method.invoke(obj, args[0]);
System.out.println("动态代理:执行操作-可以修改返回值");
return ob;
}
return null;
}
}
区别
他们两个都是代理,那么在使用时有什么区别呢?
静态代理和动态代理都是要创建代理对象,以达到某些目的。
区别就是:
- 动态代理只试用于被代理对象是接口的情况,为什么呢?
因为动态代理在创建代理对象的时候会检测对象是否实现了接口,如果没有则报空指针错误。 - 静态代理需要为每个代理对象编写代理类,而动态代理则不用。动态代理更加灵活。
参考文章:http://weishu.me/2016/01/28/understand-plugin-framework-proxy-hook/
动态代理生成的class文件
其中包括:你的接口中的方法、Object类中的 toString()、equals()、hashCode()
如何生成?
在你执行动态代理代码的地方加上:
try {
Field field = null;
field = System.class.getDeclaredField("props");
field.setAccessible(true);
Properties props = null;
props = (Properties) field.get(null);
props.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
会在 com/sun/proxy
文件夹下生成 class 文件
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.weishu.upf.dynamic_proxy_hook.app2.Shopping;
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 Shopping {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
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})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final Object[] doShopping(long var1) throws {
try {
return (Object[])super.h.invoke(this, m3, new Object[]{Long.valueOf(var1)});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
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)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m3 = Class.forName("com.weishu.upf.dynamic_proxy_hook.app2.Shopping").getMethod("doShopping", new Class[]{Long.TYPE});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
仔细看看上面的代码!