SPRING aop 代码演示

本文详细解析了面向切面编程(AOP)中的切入点(PointCut)概念及其表达式语法,涵盖了execution、args、this、target、within等多种表达式类型,并通过实例展示了如何在Java环境中配置与使用这些表达式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@PointCut 表达式详解

PointCut:切入点,指哪些方法需要被执行AOP,PointCut表达式可以有以下几种方式:

格式:@ 注解(value=“表达标签 ( 表达式格式)”)
如:@Pointcut (value=“execution(* com.cn.spring.aspectj.NotVeryUsefulAspectService.*(…))”)

表达式标签

  • execution():用于匹配方法执行的连接点
  • args(): 用于匹配当前执行的方法传入的参数为指定类型的执行方法
  • this(): 用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
  • target(): 用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
  • within(): 用于匹配指定类型内的方法执行;
  • @args():于匹配当前执行的方法传入的参数持有指定注解的执行;
  • @target():用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
  • @within():用于匹配所以持有指定注解类型内的方法;
  • @annotation:用于匹配当前执行方法持有指定注解的方法;

其中execution 是用的最多的,

execution

execution格式:

execution(

modifier-pattern?
ret-type-pattern
declaring-type-pattern?
name-pattern(param-pattern)
throws-pattern?

)

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

其中带 ?号的 modifiers-pattern?,declaring-type-pattern?,hrows-pattern?是可选项
ret-type-pattern,name-pattern, parameters-pattern是必选项;

  • modifier-pattern? 修饰符匹配,如public 表示匹配公有方法
  • ret-type-pattern 返回值匹配,* 表示任何返回值,全路径的类名等
  • declaring-type-pattern? 类路径匹配
  • name-pattern 方法名匹配,* 代表所有,set*,代表以set开头的所有方法
  • (param-pattern) 参数匹配,指定方法参数(声明的类型),

         (..)代表所有参数,

         ()代表一个参数,

         (,String)代表第一个参数为任何值,第二个为String类型.

  • throws-pattern? 异常类型匹配

例子:

  • execution(public * *(..)) 定义任意公共方法的执行
  • execution(* set*(..)) 定义任何一个以"set"开始的方法的执行
  • execution(* com.xyz.service.AccountService.*(..)) 定义AccountService 接口的任意方法的执行
  • execution(* com.xyz.service.*.*(..)) 定义在service包里的任意方法的执行
  • execution(* com.xyz.service ..*.*(..)) 定义在service包和所有子包里的任意类的任意方法的执行
  • execution(* com.test.spring.aop.pointcutexp…JoinPointObjP2.*(…)) 定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:

说明:最靠近(..)的为方法名,靠近.∗(..))的为类名或者接口名,如上例的JoinPointObjP2.∗(..))

AspectJ类型匹配的通配符:

  • * 匹配任何数量字符;
  • . . 匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
  • +:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

如:

  • java.lang.String 匹配String类型;
  • java.*.String 匹配java包下的任何“一级子包”下的String类型;如匹配java.lang.String,但不匹配java.lang.ss.String
  • java..* 匹配java包及任何子包下的任何类型; 如匹配java.lang.String、java.lang.annotation.Annotation
  • java.lang.*ing 匹配任何java.lang包下的以ing结尾的类型;
  • java.lang.Number+ 匹配java.lang包下的任何Number的自类型;如匹配java.lang.Integer,也匹配java.math.BigInteger

within和@within

  • within(com.test.spring.aop.pointcutexp.*) pointcutexp包里的任意类.
  • within(com.test.spring.aop.pointcutexp…*) pointcutexp包和所有子包里的任意类.
  • @within(org.springframework.transaction.annotation.Transactional) 带有@Transactional标注的所有类的任意方法.

this

  • this(com.test.spring.aop.pointcutexp.Intf) 实现了Intf接口的所有类,如果Intf不是接口,限定Intf单个类.

当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型.

@target

  • @target(org.springframework.transaction.annotation.Transactional) 带有@Transactional标注的所有类的任意方法.

@annotation

  • @annotation(org.springframework.transaction.annotation.Transactional) 带有@Transactional标注的任意方法.

@within和@target针对类的注解,@annotation是针对方法的注解

args 和 @args

  • @args(org.springframework.transaction.annotation.Transactional) 参数带有@Transactional标注的方法.
  • args(String) 参数为String类型(运行是决定)的方法.

Pointcut定义时,还可以使用&&、∣∣、!运算符

代码演示:

@Aspect
@Component
public class LogAspects {

    //抽取公共的切入点表达式
    //1、本类引用
    //2、其他的切面引用
    @Pointcut("execution(public int com.springboot.test.aop.MyCalculator.*(..))")
    public void pointCut(){};

    //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
    @Before("pointCut()")
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+ Arrays.asList(args)+"}");
    }

    @After("pointCut()")
    public void logEnd(JoinPoint joinPoint){
        System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
    }

    //JoinPoint一定要出现在参数表的第一位
    @AfterReturning(value="pointCut()",returning="result")
    public void logReturn(JoinPoint joinPoint,Object result){
        System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
    }

    @AfterThrowing(value="pointCut()",throwing="exception")
    public void logException(JoinPoint joinPoint,Exception exception){
        System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
    }

    @Around(value="pointCut()")
    public Object logAround(ProceedingJoinPoint joinPoint) {
        System.out.println("@Around before proceed");
        Object proceed = null;
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("@Around after proceed ");
        return proceed;
    }

}

注意点:

1.环绕通知的入参一定是ProceedingJoinPoint。和其它的几个通知不一样。

2.环绕通知的方法的返回值一定不要是void,最好是object(即使你的方法是没有返回的,那么void的时候返回为null,不会报错)。

### 关于 Spring AOP代码示例 #### 使用 `@Aspect` 注解定义切面 为了展示如何利用 Spring AOP 创建一个简单的日志记录功能,下面是一个基本的例子: ```java import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component @Aspect public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logMethodCall() { System.out.println("Method has been called."); } } ``` 这段代码展示了如何使用 `@Aspect` 和 `@Before` 来创建一个前置通知,在任何匹配的方法执行之前打印一条消息。 #### 定义服务接口和服务实现类 接下来是服务层的一个简单例子,其中包含了实际业务逻辑的服务接口及其具体实现[^4]。 ```java package com.example.service; public interface MyService { String performAction(String input); } @Service public class MyServiceImpl implements MyService { @Override public String performAction(String input) { System.out.println("Performing action with: " + input); if ("error".equals(input)) { throw new RuntimeException("Simulated error"); } return "Processed " + input; } } ``` 此部分演示了一个名为 `MyService` 接口以及它的默认实现 `MyServiceImpl`。当传入参数 `"error"` 时会触发异常处理机制。 #### 配置应用程序上下文 为了让上述组件能够正常工作,还需要配置好 Spring 应用程序上下文来扫描并注册这些 Bean: ```xml <context:component-scan base-package="com.example"/> <aop:aspectj-autoproxy/> ``` 或者采用 Java Config 方式替代 XML 文件中的设置: ```java @Configuration @EnableAspectJAutoProxy @ComponentScan(basePackages = {"com.example"}) public class AppConfig {} ``` 以上就是基于注解驱动的方式完成的日志记录切面与目标对象之间的集成过程。通过这种方式可以在不改变原有业务逻辑的前提下轻松添加新的行为特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值