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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shaohe18362202126/article/details/81638192

一、简介

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

二、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>
	 * 1.@Before 标记的方法的方法体.<br>
	 * 2.@Before 里面的是切入点表达式<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: 环绕通知, 围绕着方法执行

猜你喜欢

转载自blog.csdn.net/shaohe18362202126/article/details/81638192