欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring学习笔记——(4)AOP(一)

程序员文章站 2022-06-05 09:13:54
...

一、简介

  • AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.
  • AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.
  • 在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.
  • AOP 的好处:每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级。 业务模块更简洁, 只包含核心业务代码.

二、AOP示例

Spring学习笔记——(4)AOP(一)

三、AOP术语

1、  切面(Aspect)

  • 切面由切点和增强(引介)组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
  • 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象,如上述的验证、日志

2、通知、增强(Advice)

  • 切面必须要完成的工作,切面中的具体的功能,如上述的前置日志、后置日志和验证参数。
  • 是织入到目标类连接点上的一段程序代码。比如:添加日志、管理事务。

3、目标(Target)

  • 增强逻辑的织入目标类。如果没有AOP,目标业务类需要自己实现所有逻辑,而在AOP的帮助下,目标业务类只实现那些非横切逻辑的程序逻辑,而性能监视和事务管理等这些横切逻辑则可以使用AOP动态织入到特定的连接点上。
  • 被通知的对象,如上述的add方法,sub方法等,被加入功能的对象(java中一切皆对象)

4、代理(Proxy)

  • 一个类被AOP织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。
  • 向目标对象应用通知之后创建的对象

5、连接点(Joinpoint)

  • 程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。一个类或一段程序代码拥有一些具有边界性质的特定点,这些点中的特定点就称为“连接点”。Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 ArithmethicCalculator#add() 方法执行前的连接点,执行点为 ArithmethicCalculator#add(); 方位为该方法执行前的位置

6、切点(pointcut)

  • 每个类都拥有多个连接点:例如 ArithmethicCalculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
  • Spring AOP的规则解析引擎负责切点所设定的查询条件,找到对应的连接点。其实确切地说,不能称之为查询连接点,因为连接点是方法执行前、执行后等包括方位信息的具体程序执行点,而切点只定位到某个方法上,所以如果希望定位到具体连接点上,还需要提供方位信息。 

7、织入(Weaving)

织入是将增强添加对目标类具体连接点上的过程。AOP像一台织布机,将目标类、增强或引介通过AOP这台织布机天衣无缝地编织到一起。根据不同的实现技术,AOP有三种织入的方式:

  •     a、编译期织入,这要求使用特殊的Java编译器。
  •     b、类装载期织入,这要求使用特殊的类装载器。
  •     c、动态代理织入,在运行期为目标类添加增强生成子类的方式。
  •     Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

8、引介(Introduction)

引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。    

四、AspectJ

1、AspectJ介绍

  • AspectJ:Java 社区里最完整最流行的 AOP 框架.
  • 在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP

2、在Spring中配置AspectJ

(1)引入jar包

<!-- https://mvnrepository.com/artifact/aspectj/aspectjrt -->
<dependency>
	<groupId>aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>1.5.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.6.8</version>
</dependency>

(2)Spring配置自动扫描包,和使 AspectJ 的注解起作用

当 Spring IOC 容器侦测到 Bean 配置文件中的 <aop:aspectj-autoproxy> 元素时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理.

<!-- 自动扫描的包 -->
<context:component-scan base-package="com.shaohe.spring.aop.helloword"></context:component-scan>

<!-- 使 AspectJ 的注解起作用 :自动为匹配的类生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>	

(3)创建切面


@Aspect // 声明类为一个切面
@Component // 类交由IOC容器管理
public class LoggingAspect {

	/**
	 * 前置通知,在目标方法开始之前执行。<br>
	 * aaa@qq.com 标记的方法的方法体.<br>
	 * aaa@qq.com 里面的是切入点表达式<br>
	 * 3.JoinPoint 类型的参数:从中可以访问到方法的签名和方法的参数.
	 */
	@Before("execution(public int com.shaohe.spring.aop.helloword.ArithmeticCalculator.*(int, int))")
	public void beforeMethod(JoinPoint joinPoint) {
		// 方法名称
		String methodName = joinPoint.getSignature().getName();
		// 参数数组
		Object[] args = joinPoint.getArgs();
		System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
	}

	/**
	 * 后置通知:@After,在方法执行之后执行的代码.
	 */
	@After("execution(* com.shaohe.spring.aop.helloword.*.*(..))")
	public void afterMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		System.out.println("The method " + methodName + " ends");
	}
}

3、总结:

  • 要在 Spring 中声明 AspectJ 切面, 只需要在 IOC 容器中将切面声明为 Bean 实例. 当在 Spring IOC 容器中初始化 AspectJ 切面之后, Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理.
  • 在 AspectJ 注解中, 切面只是一个带有 @Aspect 注解的 Java 类. 
  • 通知是标注有某种注解的简单的 Java 方法.
  • AspectJ 支持 5 种类型的通知注解: 

@Before: 前置通知, 在方法执行之前执行
@After: 后置通知, 在方法执行之后执行 
@AfterRunning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@Around: 环绕通知, 围绕着方法执行

相关标签: Spring AOP