代理模式详解
在学习spring的时候发现spring的aop底层用的就是代理模式,JDK,CGLIB代理方式,研究了一下,总结一下自己的理解。
代理模式分为静态代理和动态代理,核心思想就是在原有的方法上做出增强,而aop正好切合了这个思想,就借用代理模式进行实现。
静态代理是在编译期间就需要完成的,编译完成了之后程序就已经知道了你的代理对象是谁,这样一旦代理对象很多的话,就会造成代码冗余不好维护。
package model;
interface Speaker{
void speak();
}
class ZhangShan implements Speaker{
@Override
public void speak() {
System.out.println("我老婆打我!");
}
}
class Lawyer implements Speaker{
private ZhangShan zhangShan;
public Lawyer(ZhangShan zhangShan) {
this.zhangShan = zhangShan;
}
@Override
public void speak() {
System.out.println("法律条文!");
zhangShan.speak();
System.out.println("道德批判!");
}
}
public class ProXY {
public static void main(String[] args) {
Speaker speaker=new Lawyer(new ZhangShan());
speaker.speak();
}
}
这里layer通过实现相同的speaker接口,注入张三,代替张三进行speak,曾强了张三的speak方法。但是要是出现李四,王五怎么办,每个人都写一个代理对象吗?太复杂了!
可以用动态代理,在运行区才会知道你代理的对象是谁。
package model;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Speaker{
void speak();
}
class ZhangShan implements Speaker{
@Override
public void speak() {
System.out.println("我老婆打我!");
}
}
class Lawyer implements Speaker{
private ZhangShan zhangShan;
public Lawyer(ZhangShan zhangShan) {
this.zhangShan = zhangShan;
}
@Override
public void speak() {
System.out.println("法律条文!");
zhangShan.speak();
System.out.println("道德批判!");
}
}
class LawyerProxy implements InvocationHandler{
private Object obj;
public LawyerProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("speak")){
System.out.println("法律条文!");
method.invoke(obj,args);
System.out.println("道德批判!");
}
return null;
}
}
public class ProXY {
public static void main(String[] args) {
//静态
Speaker speaker=new Lawyer(new ZhangShan());
speaker.speak();
//动态
LawyerProxy lawyerProxy=new LawyerProxy(new ZhangShan());
Speaker speaker1= (Speaker) Proxy.newProxyInstance(ProXY.class.getClassLoader(),new Class[]{Speaker.class},lawyerProxy);
speaker1.speak();
}
}
动态代理实现JDK提供的InvocationHandler接口,重写方法,从字节码层面拿到需要的数据,就不会像静态代理一样写死了,后面用proxy.newProxyInstance方法创建接口的实现类。
但是以上都是基于接口实现的代理,要是没有接口怎么办呢?
用CGLIB,他的对JDK的一个补充,不要求实现接口。
CGLIB的方式和JDK代码几乎相同,就不做演示。