AOP的概念
AOP(Aspect Oriented Programming)是一种编程范式,通过预编译方式和运行期间动态代理实现程序功能的统一维护。它是对面向对象编程(OOP)的补充,弥补了OOP在处理横切关注点(cross-cutting concerns)时的不足。
AOP的作用
- 对业务逻辑的各个部分进行隔离,降低业务逻辑的耦合度,提高程序的可重用性和开发效率。
- 在不修改源代码的情况下,对方法进行功能增强,例如日志记录、性能统计、安全控制、事务处理和异常处理等。
AOP的核心概念
目标对象:
目标对象是代理的目标对象,AOP代理可以直接使用容器中的其他bean实例作为目标。
连接点(JoinPoint):
连接点是程序中的某个点,通常是方法调用。AOP通过拦截连接点来执行特定的逻辑。(所有可以被增强的方法)
切入点(Pointcut):
定义了哪些连接点会被拦截(被功能增强的方法)
通知:
通知定义了在连接点上执行的操作,可以是前置通知、后置通知、异常通知等。(也就是在切入点目标方法前后需要执行的增强代码操作,一般都是需要增强的公共功能代码 )
通知类:
通知方法所在的类叫做通知类,该通知类一般最终会升级为切面类
切面:
切面是AOP的核心概念,它定义了横切关注点的逻辑,包括通知和切点。(描述通知与切入点的对应关系 )
AOP通知类型
名称 | 注解 | 类型 | 使用位置 | 作用 |
前置通知 | @Before | 方法注解 | 通知方法定义上方 | 在切入点方法执行之前执行 |
后置通知 | @AfterReturning | 方法注解 | 通知方法定义上方 | 在切入点方法执行之后执行,如果切入点方法内部出现异常将不会执行。 |
最终通知 | @After | 方法注解 | 通知方法定义上方 | 当前通知方法在原始切入点方法后(不管是否出现异常)运行 |
异常通知 | @AfterThrowing | 方法注解 | 通知方法定义上方 | 当前通知方法在原始切入点方法运行抛出异常后执行 |
环绕通知 | @Around | 方法注解 | 通知方法定义上方 | 当前通知方法在原始切入点方法前后运行 |
环绕通知的注意事项:
- 必须依赖形参
ProceedingJoinPoint :环绕通知必须依赖形参ProceedingJoinPoint 才能实现对原始方法的调用。在通知方法中,可以使用ProceedingJoinPoint 对象来调用被拦截的方法。 - 必须显式调用原始方法:在环绕通知中,必须显式地调用原始方法,否则原始方法将不会被执行。通过
ProceedingJoinPoint 对象的proceed() 方法可以调用原始方法,并传递任何必要的参数。 - 处理返回值和异常:环绕通知可以接收原始方法的返回值,并根据需要对其进行处理。如果原始方法抛出异常,环绕通知也可以捕获该异常并进行相应的处理。需要注意的是,如果环绕通知没有显式地处理异常,异常将会被抛出到上层调用栈。
- 注意通知的执行顺序:如果同一个切点匹配了多个通知,那么这些通知的执行顺序是由AOP框架决定的。环绕通知会优先于其他通知之前执行,因此需要注意通知之间的执行顺序和可能的相互影响。
- 确保通知方法返回值类型正确:环绕通知方法的返回值类型必须与原始方法的返回值类型兼容。如果原始方法的返回值类型是
void ,则环绕通知方法的返回值类型可以是void 或Object 。如果原始方法有返回值,环绕通知方法的返回值类型最好设定为Object ,以便能够接收和处理任何类型的返回值。
AOP的实现机制:
AOP(Aspect Oriented Programming)的底层原理是使用动态代理。动态代理是一种在运行时创建代理对象的技术,通过代理对象拦截目标方法的调用,并由代理对象控制对目标方法的引用。
AOP框架(如Spring AOP)利用动态代理实现AOP,有以下两种方式:
- JDK动态代理:JDK动态代理适用于实现了接口的类。AOP框架通过为目标对象创建一个代理对象,并由代理对象实现与目标对象相同的接口,从而实现对目标方法的拦截。
- CGLib代理:CGLib代理适用于没有实现接口的类。AOP框架使用CGLib库在运行时创建目标对象的子类,并在子类中实现拦截逻辑。
AOP的工作流程
AOP(Aspect Oriented Programming)的工作流程涉及到Spring框架的加载和代理机制。以下是AOP工作流程的简要概述:
- Spring容器启动:在Spring容器启动时,会加载需要被增强的类(如目标业务类)和通知类(如切面类)。此时,bean对象还没有被创建。
- 读取切面配置:Spring容器会读取切面配置文件中的信息,包括切入点(Pointcut)和通知(Advice)的定义。切入点指定了哪些方法需要被增强,而通知定义了增强的具体内容。
- 初始化bean:Spring容器开始初始化bean对象。在实例化bean对象之前,会判断bean对应的类中的方法是否匹配到任意切入点。如果匹配成功,说明该方法需要进行增强。
- 创建代理对象:对于需要增强的bean,Spring容器会为其创建一个代理对象。代理对象可以是JDK动态代理对象(针对接口)或CGLIB代理对象(针对类)。
- 拦截方法调用:当应用程序调用目标方法时,实际上是通过代理对象来调用的。代理对象会拦截对目标方法的调用,并根据切面配置中的通知类型执行相应的增强逻辑。
- 执行通知逻辑:代理对象会根据通知类型(如前置通知、后置通知、环绕通知等)执行相应的增强逻辑。这可以包括在方法调用前后插入自定义代码、修改方法参数或返回值等。
- 调用目标方法:在执行完通知逻辑后,代理对象会调用目标方法(即原始的业务方法),并将执行结果返回给应用程序。
AOP的使用场景
AOP(Aspect Oriented Programming)的使用场景包括以下几个方面:
- 事务管理:AOP通过声明式事务管理,简化了事务处理的代码,同时提供了统一的异常处理和事务管理机制。
- 日志操作记录:通过AOP,可以方便地对方法进行日志操作记录,以便于追踪方法的调用情况和执行结果。
- 异常处理:通过AOP,可以统一处理方法中的异常,避免异常的分散处理,提高代码的可维护性。
- 缓存:AOP可用于实现缓存机制,提高方法的执行效率。
- 权限安全认证:通过AOP,可以方便地对方法进行权限控制,确保只有具有相应权限的用户才能调用该方法。
- 持久化:AOP可用于实现对象的持久化,将对象保存到数据库或文件系统中。
- 同步:AOP可用于实现线程同步,确保多线程环境下的数据一致性和线程安全。
- 懒加载:AOP可用于实现对象的懒加载,即在需要使用对象时才进行加载,提高程序的性能和效率。
- 性能监控:AOP可用于监控方法的执行时间和其他性能指标,以便于分析和优化代码。