携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
简介
定义:
为其他对象提供一种代理以控制对这个对象的访问
代理模式的定义比较简洁,可能不熟悉代理模式的同学比较难以理解,但是对于大部分学后台的同学应该对代理模式还是比较熟悉的。简单来说就是为已有对象通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
在我们生活中也能经常见到代理模式的出现,差不多有关代理的都是一种代理模式。比如委托律师打打官司,律师就是对委托人的代理,然后很多外国产品在国内的代理商,等等。由此可见经过代理之后,代理类相对于委托类是由增强的和改动的。
案例
那我们通过代码中来看,代理模式要怎么实现。代理一般分为静态代理和动态代理。
静态代理
定义一个【人】的接口,它有一个【说话】的接口
public interface IPerson {
void speak();
}
然后定义一个法外狂徒张三去实现IPerson
public class Zhangsan implements IPerson {
@Override
public void speak() {
System.out.println("zhangsan speak");
}
}
这个时候法外狂徒张三犯事了,找了个代理律师帮他辩护。那律师要怎么了解这个案件呢,需要那些个张三来给他描述下案件,所以要将某个张三(IPerson)注入进来。
public class Lawyer implements IPerson {
private IPerson person;
public Lawyer(IPerson person) {
this.person = person;
}
@Override
public void speak() {
System.out.println("lawyer speak start");
person.speak();
System.out.println("lawyer speak end");
}
}
那既然是要给张三辩护,那把张三传进来给律师说道说道吧
public class App {
public static void main(String[] args) {
Lawyer lawyer = new Lawyer(new Zhangsan());
lawyer.speak();
}
}
静态代理还是比较简单的,可能我们很多同学平时都用过这个模式,但是并没有意识到这是静态代理。
JDK动态代理
动态代理的玩法相对复杂一点,主要依赖于InvocationHandler这个类。新建一个JdkProxy类,新增一个newProxy方法,用于创建代理类,主要是这个方法比较关键,大家要多关注这个方法,及时不好理解,暂时记住把。然后还要重写invoke方法,对委托类进行功能增强。
public class JdkProxy implements InvocationHandler {
private Object target;
public Object newProxy(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("proxy start");
Object invoke = method.invoke(target, args);
System.out.println("proxy end");
return invoke;
}
}
应用类就很简单了,直接直接创建一个代理类然后调用方法即可。
public class App {
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy();
IPerson o = (IPerson)jdkProxy.newProxy(new Zhangsan());
o.speak();
}
}
CGlib动态代理
CGlib动态代理是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式。但是这种方式不能代理final修饰的类。
总结
静态代理相对来说还是比较好理解的,通过一个构造注入委托类即可实现代理类的增强。而JDK动态代理则需要熟悉理解InvocationHandler这个类才能真正熟悉这种模式,至于CGlib动态代理则通过通过实现MethodInterceptor接口实现,在spring新的版本中使用比较多,我们后续再详细介绍。