静态代理
首先简单的说下代理模式,代理可以看做是中介,我们在租房子的时候一般都不是直接找房东租房,而是找中介租房,这个场景中房东就是被中介代理的对象,我们在租房的时候中介帮我们完成我们和房东直接租房的流程,包括看房子介绍房子签合同等等
然后再将一下静态代理和动态代理,静态代理就是通过硬编码写的代理流程,这里简单得通过代码了解一下就知道了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package proxy;
public class staticproxy { public static void use(weapon weapon) { weapon.attack(); }
public static void main(String[] args) { weapon taidao = new taidao(); System.out.println("代理之前"); use(taidao); System.out.println("代理之前"); use(new weaponagent(taidao)); } }
interface weapon { public void attack();
}
class taidao implements weapon {
@Override public void attack() { System.out.println("Use taidao attack"); } }
class weaponagent implements weapon { private weapon target;
public weaponagent(weapon target) { this.target = target; }
@Override public void attack() { System.out.println("Shift the taidao"); this.target.attack(); } }
|
这里的taidao类就可以理解为房东,weaponagent可以理解为中介,然后staticproxy就是我们自己,在代理之前我们是直接通过use调用的taidao对象然后返回一个Use taidao attack
之后我们将这个taidao对象交个weaponagent中介,然后我们调用这个中介weaponagent的use方法,他就执行的是如下代码
帮我们调用了taidao对象的attack方法,以及调用该方法是需要的一切准备操作
这就是动态代理
优点:
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- 公共的业务由代理来完成 . 实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
缺点 :
- 一个真是类对应一个代理角色,代码量翻倍,开发效率降低 .
动态代理
静态代理是一个房东对应一个租客,而动态代理则是一个中介对应多个房东,并且这个房东也就是被代理的对象是一个接口,而不是代理的具体一个对象,代理类是动态生成的,我们传入进去的就只有一个接口
同样也是举个例子看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package proxy;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class dynamicproxy {
public static void main(String[] args) { tachi tachi = new tachi(); System.out.println("代理之前"); tachi.attack();
System.out.println("代理之后"); ClassLoader classloader = tachi.getClass().getClassLoader(); Class<?>[] interfaces = tachi.getClass().getInterfaces(); InvocationHandler invocation = new swordagent(tachi);
weapon proxy = (weapon) Proxy.newProxyInstance(classloader, interfaces, invocation); proxy.attack(); } }
class tachi implements weapon{
public void attack() { System.out.println("Use taidao attack"); }
}
class swordagent implements InvocationHandler { private Object target;
public swordagent(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Shift the tachi"); return method.invoke(target, args); } }
|
这里要介绍几个类
首先是Proxy类,他是用来生成代理对象的类,里面的静态方法newProxyInstance就是用来生成的
1 2 3
| public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
|
该方法接受三个参数
- loader:代理对象使用的类加载器
- interfaces:代理对象所实现的接口
- InvocationHandler:代理对象的调用处理程序,执行代理对象的任意方法的具体实现类
接着是InvocationHandler,他是一个接口,只有一个方法invoke
里面接受三个参数
- proxy – 调用该方法的代理对象
- method -所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
- args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
这个处理程序可以理解为静态代理的中介,是具体执行具体代理操作的类,我们可以自己手动编写实现这个接口,然后在invoke方法里面编写调用代理对象某方法的逻辑
当然InvocationHandler也就收代理对象,所以InvocationHandler的实现类是执行操作的核心类,而Proxy类是一个用来动态生成代理对象的类
代理应用
动态代理在反序列化中的应用最明显的就是Lazymap的CC1链,AnnotationInvocationHandler这个类的invoke方法里面的代码能够触发恶意方法,而这个invoke方法可以理解为反序列化中的readObject方法,是可以被自动调用的,只是触发条件不同,一个是在对象被反序列化的时候自动调用,一个是对象如果是代理对象时在执行任意方法时自动调用