Spring中的IOC与AOP的理解(2)

AOP的概念

AOP(Aspect Oriented Programming)是一种编程范式,通过预编译方式和运行期间动态代理实现程序功能的统一维护。它是对面向对象编程(OOP)的补充,弥补了OOP在处理横切关注点(cross-cutting concerns)时的不足。

AOP的作用

  1. 对业务逻辑的各个部分进行隔离,降低业务逻辑的耦合度,提高程序的可重用性和开发效率。
  2. 在不修改源代码的情况下,对方法进行功能增强,例如日志记录、性能统计、安全控制、事务处理和异常处理等。

AOP的核心概念

目标对象:

目标对象是代理的目标对象,AOP代理可以直接使用容器中的其他bean实例作为目标。

连接点(JoinPoint):

连接点是程序中的某个点,通常是方法调用。AOP通过拦截连接点来执行特定的逻辑。(所有可以被增强的方法)

切入点(Pointcut):

定义了哪些连接点会被拦截(被功能增强的方法)

通知:

通知定义了在连接点上执行的操作,可以是前置通知、后置通知、异常通知等。(也就是在切入点目标方法前后需要执行的增强代码操作,一般都是需要增强的公共功能代码 )

通知类:

通知方法所在的类叫做通知类,该通知类一般最终会升级为切面类

切面:

切面是AOP的核心概念,它定义了横切关注点的逻辑,包括通知和切点。(描述通知与切入点的对应关系 )

AOP通知类型

名称 注解 类型 使用位置 作用
前置通知 @Before 方法注解 通知方法定义上方 在切入点方法执行之前执行
后置通知 @AfterReturning 方法注解 通知方法定义上方 在切入点方法执行之后执行,如果切入点方法内部出现异常将不会执行。
最终通知 @After 方法注解 通知方法定义上方 当前通知方法在原始切入点方法后(不管是否出现异常)运行
异常通知 @AfterThrowing 方法注解 通知方法定义上方 当前通知方法在原始切入点方法运行抛出异常后执行
环绕通知 @Around 方法注解 通知方法定义上方 当前通知方法在原始切入点方法前后运行

环绕通知的注意事项:

  • 必须依赖形参ProceedingJoinPoint:环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用。在通知方法中,可以使用ProceedingJoinPoint对象来调用被拦截的方法。
  • 必须显式调用原始方法:在环绕通知中,必须显式地调用原始方法,否则原始方法将不会被执行。通过ProceedingJoinPoint对象的proceed()方法可以调用原始方法,并传递任何必要的参数。
  • 处理返回值和异常:环绕通知可以接收原始方法的返回值,并根据需要对其进行处理。如果原始方法抛出异常,环绕通知也可以捕获该异常并进行相应的处理。需要注意的是,如果环绕通知没有显式地处理异常,异常将会被抛出到上层调用栈。
  • 注意通知的执行顺序:如果同一个切点匹配了多个通知,那么这些通知的执行顺序是由AOP框架决定的。环绕通知会优先于其他通知之前执行,因此需要注意通知之间的执行顺序和可能的相互影响。
  • 确保通知方法返回值类型正确:环绕通知方法的返回值类型必须与原始方法的返回值类型兼容。如果原始方法的返回值类型是void,则环绕通知方法的返回值类型可以是voidObject。如果原始方法有返回值,环绕通知方法的返回值类型最好设定为Object,以便能够接收和处理任何类型的返回值。

AOP的实现机制:

AOP(Aspect Oriented Programming)的底层原理是使用动态代理。动态代理是一种在运行时创建代理对象的技术,通过代理对象拦截目标方法的调用,并由代理对象控制对目标方法的引用。

AOP框架(如Spring AOP)利用动态代理实现AOP,有以下两种方式:

  1. JDK动态代理:JDK动态代理适用于实现了接口的类。AOP框架通过为目标对象创建一个代理对象,并由代理对象实现与目标对象相同的接口,从而实现对目标方法的拦截。
  2. CGLib代理:CGLib代理适用于没有实现接口的类。AOP框架使用CGLib库在运行时创建目标对象的子类,并在子类中实现拦截逻辑。

AOP的工作流程

AOP(Aspect Oriented Programming)的工作流程涉及到Spring框架的加载和代理机制。以下是AOP工作流程的简要概述:

  1. Spring容器启动:在Spring容器启动时,会加载需要被增强的类(如目标业务类)和通知类(如切面类)。此时,bean对象还没有被创建。
  2. 读取切面配置:Spring容器会读取切面配置文件中的信息,包括切入点(Pointcut)和通知(Advice)的定义。切入点指定了哪些方法需要被增强,而通知定义了增强的具体内容。
  3. 初始化bean:Spring容器开始初始化bean对象。在实例化bean对象之前,会判断bean对应的类中的方法是否匹配到任意切入点。如果匹配成功,说明该方法需要进行增强。
  4. 创建代理对象:对于需要增强的bean,Spring容器会为其创建一个代理对象。代理对象可以是JDK动态代理对象(针对接口)或CGLIB代理对象(针对类)。
  5. 拦截方法调用:当应用程序调用目标方法时,实际上是通过代理对象来调用的。代理对象会拦截对目标方法的调用,并根据切面配置中的通知类型执行相应的增强逻辑。
  6. 执行通知逻辑:代理对象会根据通知类型(如前置通知、后置通知、环绕通知等)执行相应的增强逻辑。这可以包括在方法调用前后插入自定义代码、修改方法参数或返回值等。
  7. 调用目标方法:在执行完通知逻辑后,代理对象会调用目标方法(即原始的业务方法),并将执行结果返回给应用程序。

AOP的使用场景

AOP(Aspect Oriented Programming)的使用场景包括以下几个方面:

  1. 事务管理:AOP通过声明式事务管理,简化了事务处理的代码,同时提供了统一的异常处理和事务管理机制。
  2. 日志操作记录:通过AOP,可以方便地对方法进行日志操作记录,以便于追踪方法的调用情况和执行结果。
  3. 异常处理:通过AOP,可以统一处理方法中的异常,避免异常的分散处理,提高代码的可维护性。
  4. 缓存:AOP可用于实现缓存机制,提高方法的执行效率。
  5. 权限安全认证:通过AOP,可以方便地对方法进行权限控制,确保只有具有相应权限的用户才能调用该方法。
  6. 持久化:AOP可用于实现对象的持久化,将对象保存到数据库或文件系统中。
  7. 同步:AOP可用于实现线程同步,确保多线程环境下的数据一致性和线程安全。
  8. 懒加载:AOP可用于实现对象的懒加载,即在需要使用对象时才进行加载,提高程序的性能和效率。
  9. 性能监控:AOP可用于监控方法的执行时间和其他性能指标,以便于分析和优化代码。