【博学谷学习记录】超强总结,用心分享|Java基础分享-Spring AOP

目录

1.Spring AOP的代理机制

2.Spring AOP的连接点

3.Spring AOP的通知类型

4.Spring AOP的切面类型

5.一般切面的AOP开发

 

 

1.Spring AOP 的代理机制

Spring AOP 是 Spring 框架的核心模块之一,它使用纯 Java 实现,因此不需要专门的编译过程和类加载器,可以在程序运行期通过代理方式向目标类织入增强代码。

Spring 在运行期会为目标对象生成一个动态代理对象,并在代理对象中实现对目标对象的增强。

Spring AOP 的底层是通过以下 2 种动态代理机制,为目标对象(Target Bean)执行横向织入的。

代理技术描述
JDK 动态代理 Spring AOP 默认的动态代理方式,若目标对象实现了若干接口,Spring 使用 JDK 的 java.lang.reflect.Proxy 类进行代理。
CGLIB 动态代理 若目标对象没有实现任何接口,Spring 则使用 CGLIB 库生成目标对象的子类,以实现对目标对象的代理。

注意:由于被标记为 final 的方法是无法进行覆盖的,因此这类方法不管是通过 JDK 动态代理机制还是 CGLIB 动态代理机制都是无法完成代理的。

2.Spring AOP 连接点

Spring AOP 并没有像其他 AOP 框架(例如 AspectJ)一样提供了完成的 AOP 功能,它是 Spring 提供的一种简化版的 AOP 组件。其中最明显的简化就是,Spring AOP 只支持一种连接点类型:方法调用。您可能会认为这是一个严重的限制,但实际上 Spring AOP 这样设计的原因是为了让  Spring 更易于访问。

方法调用连接点是迄今为止最有用的连接点,通过它可以实现日常编程中绝大多数与 AOP 相关的有用的功能。如果需要使用其他类型的连接点(例如成员变量连接点),我们可以将 Spring AOP 与其他的 AOP 实现一起使用,最常见的组合就是 Spring AOP + ApectJ。 

3.Spring AOP 通知类型

AOP 联盟为通知(Advice)定义了一个 org.aopalliance.aop.Interface.Advice 接口。

Spring AOP 按照通知(Advice)织入到目标类方法的连接点位置,为 Advice 接口提供了 6 个子接口,如下表。

通知类型接口描述
前置通知  org.springframework.aop.MethodBeforeAdvice 在目标方法执行前实施增强。
后置通知 org.springframework.aop.AfterReturningAdvice 在目标方法执行后实施增强。
后置返回通知 org.springframework.aop.AfterReturningAdvice 在目标方法执行完成,并返回一个返回值后实施增强。
环绕通知 org.aopalliance.intercept.MethodInterceptor 在目标方法执行前后实施增强。
异常通知 org.springframework.aop.ThrowsAdvice 在方法抛出异常后实施增强。
引入通知 org.springframework.aop.IntroductionInterceptor 在目标类中添加一些新的方法和属性。

4.Spring AOP 切面类型

Spring 使用 org.springframework.aop.Advisor 接口表示切面的概念,实现对通知(Adivce)和连接点(Joinpoint)的管理。

在 Spring AOP 中,切面可以分为三类:一般切面、切点切面和引介切面。

切面类型接口描述
一般切面 org.springframework.aop.Advisor Spring AOP 默认的切面类型。

由于 Advisor 接口仅包含一个 Advice(通知)类型的属性,而没有定义 PointCut(切入点),因此它表示一个不带切点的简单切面。

这样的切面会对目标对象(Target)中的所有方法进行拦截并织入增强代码。由于这个切面太过宽泛,因此我们一般不会直接使用。
切点切面 org.springframework.aop.PointcutAdvisor Advisor 的子接口,用来表示带切点的切面,该接口在 Advisor 的基础上还维护了一个 PointCut(切点)类型的属性。

使用它,我们可以通过包名、类名、方法名等信息更加灵活的定义切面中的切入点,提供更具有适用性的切面。
引介切面 org.springframework.aop.IntroductionAdvisor Advisor 的子接口,用来代表引介切面,引介切面是对应引介增强的特殊的切面,它应用于类层面上,所以引介切面适用 ClassFilter 进行定义。

 

5.一般切面的 AOP 开发

当我们在使用 Spring AOP 开发时,若没有对切面进行具体定义,Spring AOP 会通过 Advisor 为我们定义一个一般切面(不带切点的切面),然后对目标对象(Target)中的所有方法连接点进行拦截,并织入增强代码。

示例 1

下面我们就通过一个简单的实例演示下一般切面的 AOP 开发流程。

1. 创建一个名为 my-spring-aop-demo 的 Java 工程,并将以下依赖引入到工程中。
  • org.springframework.core-5.3.13.jar
  • org.springframework.beans-5.3.13.jar
  • spring-context-5.3.13.jar
  • spring-expression-5.3.13.jar
  • commons.logging-1.2.jar
  • spring-aop-5.3.13.jar

2. 在 net.biancheng.c.dao 包下,创建一个名为 UserDao 的接口,代码如下。
  1. package net.biancheng.c.dao;
  2. public interface UserDao {
  3. public void add();
  4. public void delete();
  5. public void modify();
  6. public void get();
  7. }

3. 在 net.biancheng.c.dao.impl 包下,创建 UserDao 的实现类 UserDaoImpl,代码如下。
  1. package net.biancheng.c.dao.impl;
  2. import net.biancheng.c.dao.UserDao;
  3. public class UserDaoImpl implements UserDao {
  4. @Override
  5. public void add() {
  6. System.out.println("正在执行 UserDao 的 add() 方法……");
  7. }
  8. @Override
  9. public void delete() {
  10. System.out.println("正在执行 UserDao 的 delete() 方法……");
  11. }
  12. @Override
  13. public void modify() {
  14. System.out.println("正在执行 UserDao 的 modify() 方法……");
  15. }
  16. @Override
  17. public void get() {
  18. System.out.println("正在执行 UserDao 的 get() 方法……");
  19. }
  20. }

4. 在 net.biancheng.c.advice 包下,创建一个名为 UserDaoBeforeAdvice 的前置增强类,代码如下。
  1. package net.biancheng.c.advice;
  2. import org.springframework.aop.MethodBeforeAdvice;
  3. import java.lang.reflect.Method;
  4. /**
  5. * 增强代码
  6. * MethodBeforeAdvice 前置增强
  7. *
  8. * @author c语言中文网 c.biancheng.net
  9. */
  10. public class UserDaoBeforeAdvice implements MethodBeforeAdvice {
  11. @Override
  12. public void before(Method method, Object[] args, Object target) throws Throwable {
  13. System.out.println("正在执行前置增强操作…………");
  14. }
  15. }

5. 在 src 目录下创建一个 Spring 的配置文件 Beans.xml,配置内容如下。
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!--******Advisor : 代表一般切面,Advice 本身就是一个切面,对目标类所有方法进行拦截(* 不带有切点的切面.针对所有方法进行拦截)*******-->
  10. <!-- 定义目标(target)对象 -->
  11. <bean id="userDao" class="net.biancheng.c.dao.impl.UserDaoImpl"></bean>
  12. <!-- 定义增强 -->
  13. <bean id="beforeAdvice" class="net.biancheng.c.advice.UserDaoBeforeAdvice"></bean>
  14. <!--通过配置生成代理 UserDao 的代理对象 -->
  15. <bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  16. <!-- 设置目标对象 -->
  17. <property name="target" ref="userDao"/>
  18. <!-- 设置实现的接口 ,value 中写接口的全路径 -->
  19. <property name="proxyInterfaces" value="net.biancheng.c.dao.UserDao"/>
  20. <!-- 需要使用value:增强 Bean 的名称 -->
  21. <property name="interceptorNames" value="beforeAdvice"/>
  22. </bean>
  23. </beans>

Spring 能够基于 org.springframework.aop.framework.ProxyFactoryBean 类,根据目标对象的类型(是否实现了接口)自动选择使用 JDK 动态代理或 CGLIB 动态代理机制,为目标对象(Target Bean)生成对应的代理对象(Proxy Bean)。

ProxyFactoryBean 的常用属性如下表所示。

属性描述
target  需要代理的目标对象(Bean)
proxyInterfaces 代理需要实现的接口,如果需要实现多个接口,可以通过 <list> 元素进行赋值。
proxyTargetClass 针对类的代理,该属性默认取值为 false(可省略), 表示使用 JDK 动态代理;取值为 true,表示使用 CGlib 动态代理
interceptorNames 拦截器的名字,该属性的取值既可以是拦截器、也可以是 Advice(通知)类型的 Bean,还可以是切面(Advisor)的 Bean。
singleton 返回的代理对象是否为单例模式,默认值为 true。
optimize  是否对创建的代理进行优化(只适用于CGLIB)。

posted @   后来--  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示