AspectJ框架如何完成切面、切入点和通知功能,附带代码示例

本文介绍了AspectJ,一个扩展Java的AOP框架,通过插入横切关注点实现代码模块化。文章详细阐述了切面、切入点和通知的概念,以及常用的注解如@Before、@After等在AOP中的应用。还提供了使用AspectJ实现AOP功能的步骤和示例,包括在Spring项目中的集成应用。
摘要由CSDN通过智能技术生成

AspectJ是一个面向切面的框架,它扩展了Java语言,并定义了AOP(面向切面编程)语法。AspectJ通过在源代码中插入横切关注点(cross-cutting concern),实现了在不侵入代码结构的情况下对系统进行横向切分的能力。它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

一、AspectJ特性和优势

  • 成熟稳定:AspectJ自2001年发展至今,已经是一个非常成熟和稳定的框架。通常在使用时,不需要过多担心插入的字节码正确性相关的问题。
  • 灵活性:AspectJ允许在多个位置插入自定义的代码,如方法调用的位置、方法体内部、读写变量的位置、静态代码块内部以及异常处理位置的前后。它还可以直接将原位置的代码替换为自定义的代码。
  • 模块化:切面(Aspect)是AspectJ中的一个关键概念,它是一个模块化的单元,封装了横切关注点的逻辑和行为。这使得代码更加模块化,提高了代码的可维护性和可重用性。
  • 引入新接口和实现:AspectJ的引入(Introduction)功能允许开发者为现有的类添加新的接口和实现,从而扩展类的功能。

然而,AspectJ也存在一些潜在的问题,例如性能问题。AspectJ在实现AOP时,会包装一些特定的类,并不会直接将Trace函数插入到代码中,而是经过一系列的封装。这可能导致生成的字节码较大,对原函数的性能产生一定的影响。特别是在对应用中的所有函数都进行插桩时,性能影响可能会更加显著。

AspectJ的两种实现方式:

  • 使用XML的配置文件:配置全局事务。
  • 使用注解:我们在项目中要做AOP功能,一般都使用注解, AspectJ有5个注解。

1、切面、切入点和通知

在AspectJ中,切面、切入点和通知是核心概念,它们共同构成了面向切面编程(AOP)的基础。

  • 切面(Aspect):切面是从不同的角度来看待同一个事物。在AspectJ中,切面是一个模块化的单元,它封装了与 横切关注点 相关的行为。切面负责定义切点(即哪些连接点会被拦截)和通知(即拦截到连接点后执行什么逻辑)。 通过切面,开发者可以将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,使得代码更加模块化、可维护。
  • 切点(PointCut):切点用于指定哪些连接点(JoinPoint)应该被切面所影响。 连接点是程序中可能被拦截的点,例如方法调用、异常抛出等。切点表达式用于匹配这些连接点,从而确定哪些方法或操作应该被切面的通知所影响。
  • 通知(Advice):通知是切面的具体逻辑实现,由切面负责执行。 通知定义了当与切点匹配的连接点被拦截时应该执行的操作。AspectJ定义了多种通知类型,如前置通知(在方法执行前执行)、后置通知(在方法正常返回后执行)、异常通知(在方法抛出异常时执行)等。通知使得开发者能够在不修改业务逻辑代码的情况下,向业务逻辑中添加额外的行为。

在AspectJ框架中使用注解表示的。也可以使用xml配置文件中的标签。

2、AspectJ中常用的注解

  • @Aspect:这个注解用于标识一个Java类为切面类,这样AspectJ框架就能识别并处理这个类中的通知、切点等定义。
  • @Pointcut:用于定义一个切点,即指定哪些连接点(JoinPoint)应该被拦截。切点表达式描述了哪些方法或操作应该被切面的通知所影响。
  • @Before:前置通知注解,表示在目标方法执行之前执行特定的通知逻辑。
  • @After:后置通知注解,表示在目标方法执行之后(无论方法执行是否成功)执行特定的通知逻辑。
  • @AfterReturning:返回通知注解,表示在目标方法正常执行完毕后(即方法没有抛出异常)执行特定的通知逻辑。
  • @AfterThrowing:异常通知注解,表示在目标方法抛出异常时执行特定的通知逻辑。
  • @Around:环绕通知注解,它是最强大的通知类型,允许在目标方法执行前后插入自定义的逻辑,甚至可以控制目标方法的执行(例如,阻止其执行或多次执行)。
  • @Order:这个注解用于定义切面的优先级,当多个切面都匹配同一个连接点时,可以根据优先级来决定哪个切面的通知先执行。

这些注解在AspectJ中扮演着重要的角色,它们使得开发者能够以一种声明式的方式定义切面的行为,从而简化横切关注点的处理。通过使用这些注解,开发者可以将日志记录、事务管理、权限控制等横切关注点从业务逻辑中分离出来,提高代码的可维护性和可重用性。

2.1、@Before :前置通知注解

属性:value,是切入点表达式,表示切面的功能执行的位置。

位置:方法的上面。

特点:在目标方法之前先执行的,不会改变目标方法执行的结果,不会影响目标方法的执行。

2.2、@AfterReturning :后置通知注解

后置通知定义方法,方法是实现切面功能的

方法的定义要求:

  • 公共方法public
  • 方法没有返回值
  • 方法自定义名称
  • 方法有参数,推荐Object

属性:

  • value,是切入点表达式,表示切面的功能执行的位置。
  • returning,自定义的变量,表示目标方法的返回值的,自定义变量名必须和通知方法的形参名一样。

位置:方法定义的上面

特点:

  • 在目标方法之后执行的,能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能。
  • 可以修改这个返回值。
  • 后置通知的执行类似参数传递:传值、传引用。

2.3、@Around :环绕通知注解

环绕通知经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务。

环绕通知方法的定义格式:

  • public
  • 必须有一个返回值
  • 方法名称自定义
  • 方法有参数,固定的参数ProceedingJoinPoint

属性:value,是切入点表达式。

位置:在方法的定义上面

特点:

  • 他是功能最强的通知,在目标方法的前和后都能增强功能。
  • 控制目标方法是否被调用执行。
  • 修改原来的目标方法的执行结果,影响最后的调用结果。
  • 环绕通知,等同于JDK动态代理,InvocationHandler 接口,ProceedingJoinPoint 就等同于 Method

2.4、@AfterThrowing :异常通知注解

方法的定义要求:

  • 公共方法public
  • 方法没有返回值
  • 方法自定义名称
  • 方法有一个exception,如果还有就是JoinPoint

属性:

  • value,切入点表达式
  • throwing自定义的变量,表示目标方法抛出的异常对象
  • 变量名必须和方法的参数名一样。

特点:

  • 在目标方法抛出异常时执行的
  • 可以做异常的监控程序,监控目标方法执行时是不是有异常,如果有异常,可以发送邮件,短信进行通知。

异常通知类似于try…catch

try{
	SomeServiceImpl.doSecond(..}catch{
	myAfterThrowing(e)
}

2.5、@After 最终通知

一般是做资源清除工作的。

方法的定义要求:

  • 公共方法public
  • 方法没有返回值
  • 方法自定义名称
  • 方法没有参数,如果有就是JoinPoint。

属性:value,切入点表达式。

位置:在方法的上面。

特点:总是会执行,在目标方法之后执行的。

try{
	SomeServiceImpl.doThird(..}catch(Exception e){	
	         
}finally{
	myAfter(}

2.6、@Pointcut:定义和管理切入点

如果你的项目中有多个切入点表达式是重复的,可以复用的,可以使用@Pointcut。

属性:value切入点表达式。

位置:在自定义的方法上面。

特点:当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名。其它的通知中,vaLue属性就可以使用这个方法名称,代替切入点表达式了。

3、切入点表达式

切入点表达式表示切面执行的位置。

  • execution(public * *(..))
  • 指定切入点为:任意公共方法。
  • execution(* set*(..))
  • 指定切入点为:任何一个以 set 开始的方法。
  • execution(* com.xyz.service.*.*(..))
  • 指定切入点为:定义在 service 包里的任意类的任意方法。
  • execution(* com.xyz.service..*.*(..))
  • 指定切入点为:定义在 service 包或者子包里的任意类的任意方法。.. 出现在类名中时,后面必须跟 * ,表示包、子包下的所有类。
  • execution(* *..service.*.*(..))
  • 指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点

4、使用AspectJ框架实现AOP

使用AOP:目的是给已经存在的一些类和方法,增加额外的功能。前提是不改变原来的类的代码。

使用AspectJ实现AOP的基本步骤:

1、新建Maven项目。

2、加入依赖:Spring依赖,AspectJ依赖,JUnit单元测试。

3、创建目标类:接口和他的实现类。要做的是给类中的方法增加功能。

4、创建切面类:普通类,在类的上面加入@Aspect注解。在类中定义方法,方法就是切面要执行的功能代码在方法的上面加入AspectJ中的通知注解。

  • 定义方法,方法是实现切面功能的。
  • 方法的定义要求:公共方法public、方法没有返回值、方法自定义名称、方法可以有参数,也可以没有参数。
  • 如果有参数,参数不是自定义的,@Before有需要指定切入点表达式 execution()

5、创建Spring的配置文件:声明对象,把对象交给容器统一管理声明对象。你可以使用注解或者xml配置文件 <bean>

  • 声明目标对象。
  • 声明切面类对象。
  • 声明AspectJ框架中的自动代理生成器标签。

自动代理生成器:用来完成代理对象的自动创建功能的。

6、创建测试类,从Spring容器中获取目标对象(实际就是代理对象)。通过代理执行方法,实现AOP的功能增强。

三,使用AspectJ实现AOP功能示例

使用AspectJ实现AOP功能,你需要首先确保你的项目中包含了AspectJ的相关依赖。你可以定义一个切面(Aspect),并在其中声明连接点(Join Point)和通知(Advice)。

以下示例展示了如何使用AspectJ在方法执行前后打印日志:

1、定义目标接口和实现类

首先,我们定义一个简单的接口和一个实现该接口的类。

// MyService.java  
public interface MyService {  
    void doSomething();  
}  
  
// MyServiceImpl.java  
public class MyServiceImpl implements MyService {  
    @Override  
    public void doSomething() {  
        System.out.println("Doing something...");  
    }  
}

2、定义切面

接下来,我们定义一个切面,该切面会在MyService接口的doSomething方法执行前后打印日志。

// LoggingAspect.java  
import org.aspectj.lang.JoinPoint;  
import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
import org.aspectj.lang.annotation.After;  
  
@Aspect  
public class LoggingAspect {  
  
    @Before("execution(* com.example.MyService.doSomething(..))")  
    public void beforeDoSomething(JoinPoint joinPoint) {  
        System.out.println("Before method: " + joinPoint.getSignature());  
    }  
  
    @After("execution(* com.example.MyService.doSomething(..))")  
    public void afterDoSomething(JoinPoint joinPoint) {  
        System.out.println("After method: " + joinPoint.getSignature());  
    }  
}

在上面的代码中,我们使用了 @Aspect 注解来声明这是一个切面。@Before@After 注解分别定义了前置通知和后置通知,它们会在 MyService 接口的 doSomething 方法执行前后被调用。execution 表达式定义了连接点,即哪些方法会被这个切面所影响。

示例是基于AspectJ的注解风格。AspectJ还提供了XML配置风格和原生AspectJ语法,你可以根据自己的喜好和项目的需求来选择使用哪种方式。如果你使用的是Spring Boot,Spring Boot已经内置了对AspectJ的支持,你可以很容易地通过添加依赖和配置来使用AspectJ。

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值