首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【Java EE进阶 --- SpringBoot】AOP原理

【Java EE进阶 --- SpringBoot】AOP原理

作者头像
optimistic_chen
发布2026-01-14 20:43:04
发布2026-01-14 20:43:04
140
举报
上篇博客讲到Spring AOP的应用,这篇博客带你了解Spring是如何实现AOP的?

代理模式

代理模式,也叫做委托模式:为其他对象提供一种代理以控制对这个对象的访问。

作用:提供一个代理类,让程序员调用目标方法时,不再是直接对目标方法进行调用,而是通过代理类间接调用。

在这里插入图片描述
在这里插入图片描述

生活中的例子:

  • 律师:法庭上,代理辩护人进行辩护
  • 房产中介:房屋进行租凭时,房东会把房屋授权给中介,由中介代理租凭事务

代理模式中的主要角色

  1. Subject:业务接口类,可以是抽象类(调用方)
  2. RealSubject:业务实现类,具体业务逻辑实现,也就是目标方法(被代理对象)
  3. Proxy: 代理类,RealSubject的代理

客户端角度出发,它调用Subject接口定义的目标方法,并不关心这个方法的实现逻辑。 从代理模式结构出发,Proxy(代理类)没有实现目标方法,但是它可以调用目标方法并且在不修改目标方法的前提下,增加其他逻辑(功能),使得整个代码的可扩展性大大提高

在这里插入图片描述
在这里插入图片描述

静态代理

静态代理:由程序员创建代理类或特定工具自动生成源码在对其编译,在程序运行前代理类的.class文件就已经存在了。也就是在租房之前,中介就已经做好了准备工作,就等客户来“调用”了。

我们通过代码来观察一下:

定义业务接口(定义出租房子):

代码语言:javascript
复制
public interface HouseSubject{
    void rentHouse();
}

实现接口(房东出租房子):

代码语言:javascript
复制
public class RealHouseSubject implements HouseSubject{
     @Override
     public void rentHouse(){
         System,out.println("我是房东,我要出租房子");
     }
}

代理类(中介,代理房东出租房子)

代码语言:javascript
复制
public class HouseProxy implements HouseSubject{
    private HouseSubject houseSubject;
    public HouseProxy(HouseSubject houseSubject){
         this.houseSubject = houseSubject;
    }
    
    @Override
    public void rentHouse(){
         System,out.println("我是中介,开始代理");
         
         houseSubject.rentHouse();
         
         System,out.println("我是中介,结束代理");
    }
}

客户端使用方法:

代码语言:javascript
复制
public class Main{
    public static void main(String[] args){
        HouseSubject subject=new RealHouseSubject();
        //创建代理类
        HouseProxy proxy=new HouseProxy(subject);
        //通过代理类访问目标方法
        proxy.rentHouse();
    }
}

从运行结果发现,虽然静态代理都实现了目标方法的代理,但是方法的增强都是手动完成,很死板。如果以后需要增加其他接口(功能),还需要对业务实现类新增代理类。

其实这里我有一个疑问,为什么不把所有方法都写在一个类里面,这样就只有一个代理类了。

这样设计会反应出一些原则问题,比如违反一个职责原则:一个类只能表现出它本身职责;代理逻辑难以复用:代理模式的主要职责受到限制,因为不同方法需要不同的增强逻辑,不能都混在一个类里面。(比如要其中一个方法计算耗时,但是另一个方法需要事务管理,最好的方法就是动态代理+职责拆分

动态代理

动态代理:在程序运⾏时,运⽤反射机制动态创建⽽成

我们不需要针对每个对象都单独创建一个代理类,⽽是把这个创建代理对象的⼯作推迟到程序运⾏时由JVM来实现.也就是说动态代理在程序运⾏时,根据需要动态创建⽣成。(有点像懒汉模式) Java对动态代理进行了实现,并提供了一些API,常见的实现有:

  • JDK动态代理
  • CGLIB动态代理
JDK动态代理

定义接口及其实现类(HouseSubject和RealHouseSubject)

代码语言:javascript
复制
public interface HouseSubject{
    void rentHouse();
}

public class RealHouseSubject implements HouseSubject{
     @Override
     public void rentHouse(){
         System,out.println("我是房东,我要出租房子");
     }
}

自定义InvocationHandler并重写invoke方法,在invoke方法中调用目标方法(被代理方法)并自定义一些处理逻辑

代码语言:javascript
复制
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class JDKInvocationHandler implements InvocationHandler {
    //目标对象就是代理对象
    private Object target;

    public JDKInvocationHandler(Object target){
        this.target=target;
    }
     /**
     * @param proxy 代理对象
     * @param method 目标方法
     * @param args 方法对应的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理增强内容
        System.out.println("我是中介,开始代理");
        //通过反射调用被代理的方法
        Object retVal=method.invoke(target,args);
        System.out.println("我是中介,结束代理");
        return retVal;
    }
}

InvocationHandler接⼝是Java动态代理的关键接⼝之⼀,它定义了⼀个单⼀⽅法invoke(),⽤于处理被代理对象的⽅法调⽤。通过InvocationHandler接口,对被代理对象的方法进行功能增强。

客户端创建一个代理对象并使用

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        HouseSubject target=  new RealHouseSubject();
        
        //创建⼀个代理类:通过被代理类、被代理实现的接⼝、⽅法调⽤处理器来创建
        HouseSubject proxy = (HouseSubject) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//使用目标类的类加载器
                new Class[]{HouseSubject.class},//代理要实现的接口
                new JDKInvocationHandler(target)//方法调用代理类
        );
        proxy.rentHouse();
    }
}

整个流程是:

  1. JVM在运行时动态创建一个新的类(相当于静态代理的手动实现接口),这个类实现了HouseSubject接口(相当于中介的”工作证“,证明中介可以提供出租房子)
  2. 客户端调用代理对象(中介)的rentHouse()方法
  3. 进入动态生成的rentHouse()方法(客户端租房请求)
  4. 动态生成类将调用转发给代理类(中介)
  5. 进入代理类(中介)的invoke()方法
  6. 执行前置增强(开始代理)
  7. 通过反射调用目标方法method.invkoe()(中介联系房东)
  8. 进入RealHouseSubject的rentHouse()方法(出租房子)
  9. 执行后置增强功能(结束代理)
  10. 返回结果给InvocationHandler (中介完成任务)
  11. 返回结果给动态生成类 (中介向客户反馈结果)
  12. 返回客户端调用者(客户租到房子)
在这里插入图片描述
在这里插入图片描述

总结:JVM为接口中的每个方法生成相同的调用模板,所有的方法调用都通过invoke这一个入口,新增方法时 代理逻辑自动生效(method.invoke(target, args)调用实际方法),无需修改代码。

CGLIB动态代理

CGLIB是开源项目,使用需要添加相关依赖

代码语言:javascript
复制
 <dependency>
     <groupId>cglib</groupId>
     <artifactId>cglib</artifactId>
     <version>3.3.0</version>
 </dependency>

接口及其实现类同上:

自定义MethodeInterceptor 并重写intercept方法(与invoke类似)

代码语言:javascript
复制
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLIBInterceptor implements MethodInterceptor {
    //目标对象(中介)
    private Object target;

    public CGLIBInterceptor() {
        this.target=target;
    }

    /**
     * @param obj 被代理的对象(房东)
     * @param method 目标方法(增强方法)
     * @param args 方法参数
     * @param proxy 代理对象(中介)调用原始方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //代理增强内容
        System.out.println("我是中介,开始代理");
        //通过反射调用被代理的方法
        Object retVal=method.invoke(target,args);
        System.out.println("我是中介,结束代理");
        return retVal;
    }
}

客户端创建代理类:

代码语言:javascript
复制
public class DynamicMain {
    public static void main(String[] args) {
        HouseSubject target=  new RealHouseSubject();
        //被代理的接口 拦截的目标方法
        HouseSubject proxy= (HouseSubject)
                Enhancer.create(target.getClass(),new CGLIBInterceptor(target));
        proxy.rentHouse();
    }
}

总结

  • AOP和Ioc一样都是一种思想,AOP是对某一类事件的集中处理,Spring框架实现了AOP,称之为Spring AOP。
  • Spring AOP常⻅实现⽅式有两种: 1.基于注解@Aspect来实现 2.基于⾃定义注解来实现,还有⼀些更原始的⽅式:基于代理等等
  • Spring AOP是基于JDK,CGLIB动态代理实现的,运⾏时使⽤哪种⽅式与项⽬配置和代理的对象有关。

完结撒花!🎉

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-01-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代理模式
    • 代理模式中的主要角色
    • 静态代理
    • 动态代理
      • JDK动态代理
      • CGLIB动态代理
  • 总结
  • 完结撒花!🎉
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档