前言:
学习Spring源码时,其中非常重要的一点就是代理模式,今天就好好记录一下我的学习过程。
什么是代理模式:
非常直观的办法就是从UML图来分析。
从UML图我们可以清晰的看出代理模式的本质就是给某一个对象提供代理对象,并由代理对象控制对原对象的引用。
代理模式的分类:
- 静态代理
动态代理
其中,动态代理又可分为:
1.jdk动态代理
2.cglib动态代理
3.Spring和AspectJ实现的动态代理
静态代理:
静态代理的结构就如上图UML一样:
Subject类:
/**
*
* @Title:
* @Description:TODO抽象的目标接口,定义具体的目标对象和代理公用的接口
* @author sunlei
* @Date:2018-2-27上午6:42:03
*/
public interface Subject {
public void request();
}
RealSubject类:
/**
*
* @Title:
* @Description:TODO具体的目标对象,真正被代理的对象
* @author sunlei
* @Date:2018-2-27上午6:41:13
*/
public class RealSubject implements Subject{
public void request(){
//执行具体功能
}
}
Proxy类
/**
*
* @Title:
* @Description:TODO代理对象
* @author sunlei
* @Date:2018-2-27上午6:47:05
*/
public class Proxy implements Subject{
/*
* 持有被代理的具体的目标对象
*/
private RealSubject realsubject = null;
/*
* 构造方法,传入被代理的具体的目标对象
* @param realSubject:被代理的具体的目标对象
*/
public Proxy(RealSubject realSubject){
this.realsubject = realSubject;
}
@Override
public void request() {
// TODO Auto-generated method stub
/*
* 当需求更改时,不去直接修改RealSubject【遵循开闭原则】
* 而是通过Proxy去修改对RealSubject的操作
*/
//在转调具体的目标对象前,可以执行一些功能处理
//比如,某些校验功能
realsubject.request();
}
}
MyTest类:
public class MyTest {
public static void main(String[] args){
RealSubject subject = new RealSubject();
Proxy p = new Proxy(subject);
p.request();
}
}
静态代理就是为自己要代理的类写一个代理类,或者用工具为其生成的代理类。总之,就是程序运行前就已经存在的编译好的代理类。这样很多时候会显得非常麻烦,导致不灵活。相比静态代理,动态代理具有更强的灵活性。它不用再设计实现的时候就指定某一个代理类来代理那一个被代理的对象,我们可以把之中指定延迟到程序运行时由JVM来实现。
动态代理:
水平有限,此处简述JDK动态代理:
Subject类:
/**
*
* @Title:
* @Description:TODO抽象的目标接口,定义具体的目标对象和代理公用的接口
* @author sunlei
* @Date:2018-2-27上午6:42:03
*/
public interface Subject {
public void request();
}
RealSubject类:
/**
*
* @Title:
* @Description:TODO具体的目标对象,真正被代理的对象
* @author sunlei
* @Date:2018-2-27上午6:41:13
*/
public class RealSubject implements Subject{
public void request(){
//执行具体功能
}
}
MyTest类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyTest {
public static void main(String[] args){
final Subject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(),
new InvocationHandler() {
//回调方法,拦截到目标对象的时候执行
/**
* InvocationHandler接口只定义了一个invoke方法,因此对于这样的接口,我们不用单独去定义一个类来实现该接口,
* 而是直接使用一个匿名内部类来实现该接口,new InvocationHandler() {}就是针对InvocationHandler接口的匿名实现类
*/
/**
* 在invoke方法编码指定返回的代理对象干的工作
* proxy : 把代理对象自己传递进来
* method:把代理对象当前调用的方法传递进来
* args:把方法参数传递进来
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("在代理对象中拦截到:"+method.getName());
//调用拦截到的方法
Object o = method.invoke(realSubject, args);
return o;
}
});
proxy.request();
}
}
动态代理就是在运行时生成一个类,这个类会实现你指定的一组接口,而这个类没有.java文件,是在运行时生成的,你也不用去关心它是什么类型的,你只需要知道它实现了哪些接口即可。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,InvocationHandler h)
public Object invoke(Object obj, Object... args)
这两大函数为JDK动态代理的核心,但是其设计的精妙暂时不能理解。哈哈。。