Spring AOP实现原理
Spring AOP实现原理
1. 代理模式
程序为什么要代理?
- 说法1:原始对象如果觉得本类上的工作太多,可以通过代理来转移部分职责。
- 说法2:如果不改原始类的代码的情况下,可以使用代理对原始对象的功能进行增强
- 特点:原始对象的什么方法想被增强(被代理),代理类一定要有对应的方法。
代理模式UML 类图如下

类图中虚线箭头表示接口实现
菱形和箭头表示组合(组合:部分和整体的关系,并且生命周期是相同的。例如:人与手)
具体参考uml类图
代理类实现了被代理类的接口,同时与被代理类是组合关系。下面看一下代理模式的实现
2. 静态代理
例子
租客-中介-房主
代理这个词是来源于Java设计模式中的代理模式,代理模式最简单的理解就是通过第三方来代理我们的工作
比如中介,房东需要将自己的房子租出去,而租客需要租房子,三者关系如此
租客租房子一般都找不到房东,房东也不会轻易将自己暴露给广大租客,因此就需要中介来充当这个中间关系
因此租客就只能通过中介来进行租房子这个工作,不需要通过房东,这就叫做代理—-就是中介代理房东来处理租房子这件事情
观众-中介-明显

比如大明星想唱歌,唱歌这个动作不光要明星参与,还要准备场地和音响,售票等动作,观众不会直接找明星唱歌,而是找中介公司组织的演唱会,三者关系如此
观众听歌一般都找不到明星,明星也不会轻易将自己暴露给广大观众面前,因此就需要中介来充当这个中间关系
因此观众就只能通过中介来进行听明星唱歌了,这就叫做代理—-就是中介代理明星来处理唱歌这件事情


代码实现:👇 👇

1️⃣ 接口类:
public interface Star {
void sing();
}
2️⃣ 真实实体类:
public class FGStar implements Star {
private String music;
public FGStar(String content) {
this.music = content;
}
public void sing() {
System.out.println(this.music);
}
}
3️⃣ 代理类:
public class ZhongjieAgent implements Star {
// 真实类的引用
private Star actor;
private String before; //前置工作
private String after; //后置工作
//通过构造方法给真实类赋值
public ZhongjieAgent(Star actor, String before, String after) {
this.actor = actor;
this.before = before;
this.after = after;
}
public void sing() {
//代理类增强的部分
System.out.println("唱歌前准备工作:" + before);
//真实类的方法
this.actor.sing();
//代理类增强的部分
System.out.println("唱完歌后的清场工作:" + after);
}
}
测试方法:
public class StaticProxy {
public static void main(String[] args) {
//创建真实用户
Star actor = new FGStar("铁窗泪");
// 创建代理对象
Star agent = new ZhongjieAgent(actor, "售票", "清场");
// 调用代理对象的方法
agent.sing();
}
}
结果:

3.动态代理
动态代理
动态代理 就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。 在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。
可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。 👈 🍐
- 代理类在程序运行期间,创建的代理对象称之为动态代理对象。
- 这种情况下,创建的代理对象,并不是事先在Java代码中定义好的。而是在运行期间,根据我们在动态代理对象中的指示,动态生成 的实时生成,没有.class文件。 🍐
也就是说,你想获取哪个对象的代理,动态代理就会为你动态的生成这个对象的代理对象。
有了动态代理的技术,那么就可以在不修改方法源码的情况下,增强被代理对象的方法的功能,在方法执行前后做任何你想做的事情。 🍐 ❤️
实现动态代理有2种方式:
- JDK自带方法
- CGLIB 库的方法
JDK和Cglib的区别:
Cglib | JDK | |
---|---|---|
是否提供子类代理 | 是 | 否 |
是否提供接口代理 | 是(可强制) | 是 |
区别 | 必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法 | 实现InvocationHandler 使用Proxy.newProxyInstance产生代理对象 被代理的对象必须要实现接口 |
3.1 JDK自带方法
JDK自带代理
1️⃣ Proxy类的newProxyInstance方法
创建代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
其中的参数含义如下:
- loader: 被代理的类的类加载器
- interfaces: 被代理类的接口数组
- invocationHandler: 就是刚刚介绍的调用处理器类的对象实例
2️⃣ InvocationHandler接口是最核心的接口
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
我们对于被代理的类的操作都会由该接口中的invoke方法实现,其中的参数的含义分别是:
- proxy :被代理的类的实例
- method :调用被代理的类的方法
- args :该方法需要的参数
使用方法 👇 👇
使用方法首先是需要实现该接口,并且我们可以在invoke方法中调用被代理类的方法并获得返回值,自然也可以在调用该方法的前后去做一些额外的事情,从而实现动态代理
下面是一个实际例子。
3.1.3 JDK自动代理实际例子
Star接口:
public interface Star {
void dance();
}
YCYStar实现Star接口:
public class YCYStar implements Star {
public void dance() {
System.out.println("铁管舞");
}
}
public class JdkProxy implements InvocationHandler{
// 实现InvocationHandler接口,并且可以初始化被代理类的对象
private Object proxy; //被代理的类的实例
public JdkProxy(Object proxy) {
this.proxy = proxy;
}
/**
*
* @param proxy 被代理的类的实例
* @param method 调用被代理的类的方法
* @param args 该方法需要的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("售票,准备舞台...");
//真正调用方法的地方
Object ret = method.invoke(this.proxy, args);
System.out.println("清场,打扫卫生...");
return ret;
}
}
测试类:
public class ReflectTest {
public static void main(String[] args) throws Exception {
// 准备代理对象
Star o = (Star) Proxy.newProxyInstance(Star.class.getClassLoader(), new Class[]{Star.class},
new JdkProxy(new YCYStar()));
// 调用代理对象
o.dance();
}
}
结果:

可以看到对于不同的实现类来说,可以用同一个动态代理类来进行代理,实现了“一次编写到处代理”的效果。但是这种方法有个缺点,就是被代理的类一定要是实现了某个接口的,这很大程度限制了本方法的使用场景。下面还有另外一个使用了CGlib增强库的方法。
3.2 CGLIB 库的方法
CGLIB代理
Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展
CGlib是一个字节码增强库,为AOP等提供了底层支持。
CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成 final,对于 final 类或方法,是无法继承的
案例:👇 👇

1️⃣ 新建一个maven项目,并引入cglib依赖:
导入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
2️⃣ 新建一个目标类,名为RBaStar
public class RBaStar {
void dance(){
System.out.println("热巴,在热舞!!");
}
void sing(){
System.out.println("热巴,在唱歌!!");
}
}
3️⃣ 创建代理类
/**
* 代理类
*/
public class CglibAgent implements MethodInterceptor {
// 创建代理对象
public Object createProxy(Object object){
Enhancer enhancer = new Enhancer(); //创建增强内
enhancer.setSuperclass(object.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("售票,准备舞台....");
// 热巴在动作
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("清场,打扫卫生....");
return invoke;
}
}
4️⃣ 测试
