AspectJ注解


常见AspectJ的注解:

  • @Aspect 把当前类标识为一个切面
  • @Pointcut 植入Advice(通知)的触发条件。
  • @Before 前置增强,相当于BeforeAdvice,目标方法执行前执行
  • @After final增强,不管是抛出异常或者正常退出都会执行
  • @AfterReturning 后置增强,相当于AfterReturningAdvice,方法正常退出时执行
  • @AfterThrowing 异常抛出增强,相当于ThrowsAdvice,目标方法抛出异常后执行
  • @Around 环绕增强,相当于MethodInterceptor

开启切面支持

注解:

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {

}

xml:

<aop:aspectj-autoproxy/>

切面 @Aspect

配置value的知识了解:https://www.cnblogs.com/heliusKing/p/11845948.html

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {

    /**
     * 子句前缀表达式,默认为单列切面,"perthis(...)"就,针对多线程,实际业务没用过
     * 配置如value="perthis(execution(* com.helius.service.impl.*.*(..)))"
     */
    public String value() default "";
}

用例

@Aspect
@Component
public class PerformanceAspect {

}

pointcut表达式

标准Aspectj Aop 还是Spring Aop自增,参看:https://blog.csdn.net/f641385712/article/details/83543270

execute

execution([修饰符] 方法返回值 包名.[.]类名.方法名(参数) [异常])

/**
 * execution(): 表达式主体
 * 第一个*号:表示返回类型,*号表示所有的类型
 * 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.example.lx包、子孙包
 * 第二个*号:表示类名,*号表示所有的类。
 * *(..):第三个*号表示方法名,*号表示所有的方法,(..)表示方法参数,两个句点表示任何参数
 */
execution (* com.example.lx..*.*(..))

拦截所有public方法

@Pointcut("execution(public * *(..))")

拦截以save开头的所有方法

@Pointcut("execution(* save*(..))")

拦截UserService类或者接口中所有方法

@Pointcut("execution(* com.example.lx.UserService.*(..))")

拦截UserService类和UserService子类所有方法

@Pointcut("execution(* com.example.lx.UserService+.*(..))")

拦截包中定义的所有方法,不包含子包中的方法

@Pointcut("execution(* com.example.lx.*.*(..))")

拦截包和子包中定义的所有方法

@Pointcut("exection(* com.example.lx..*(..))")
//包括下面两个路径
@Pointcut("exection(* com.example.lx.*(..))")
@Pointcut("exection(* com.example.lx.a.*(..))")

通过方法参数拦截
可以使用“”和“ …”通配符,其中“”表示任意类型的参数,而“…”表示任意类型参数且参数个数不限
参数类型是java.lang包下的类,直接使用类名,否则用全限定类名,

@Pointcut("execution(* save*(String, int))")
//必须使用全限定类名
@Pointcut("execution(* save*(java.util.List, int))")
//第二参数是任意类型,但是只匹配两个参数的
@Pointcut("execution(* save*(String, *))")
//第二参数是任意类型,匹配第一个参数为String的,没有第二个参数或者多个参数均匹配
@Pointcut("execution(* save*(String, ..))")
//只有一个参数,Object类型
@Pointcut("execution(* save*(Object))")
//只有一个参数,Object类型或者Object子类
@Pointcut("execution(* save*(Object+))")

within

within( 包名.[.]*)

拦截包中所有方法

 @Pointcut("within(com.xyz.service.*)")

拦截包和子包中的所有方法

@Pointcut("within(com.xyz.service..*)")
//包括下面两个路径
@Pointcut("within(com.xyz.service.*)")
@Pointcut("within(com.xyz.service.a.*)")

this

代理对象匹配时才会被拦截
spring的对象如果实现了接口,默认使用jdk动态代理;如果没有实现接口,使用cglib动态代理
指定都用cglib动态代理 设置@EnableAspectJAutoProxy(proxyTargetClass = true)

//如果UserServiceImpl实现IUserService时,默认jdk代理不会拦截
@Pointcut("this(com.example.lx.service.impl.UserServiceImpl)")
//@EnableAspectJAutoProxy(proxyTargetClass = true),指定cglib代理时会拦截
@Pointcut("this(com.example.lx.service.impl.UserServiceImpl)")
//指定代理对象为接口,会拦截
@Pointcut("this(com.example.lx.service.impl.IUserService)")

//如果UserServiceImpl没有实现IUserService,默认是cglib代理会拦截
@Pointcut("this(com.example.lx.service.impl.UserServiceImpl)")

target

目标对象为指定的类型被拦截

//UserServiceImpl实现或者没有实现IUserService,都会拦截
 @Pointcut("target(com.example.lx.service.impl.UserServiceImpl)")

this 和 target 的不同

  1. this作用于代理对象,target作用于目标对象
  2. this表示目标对象被代理之后生成的代理对象和指定类型匹配才会拦截,匹配的是代理对象
  3. target表示目标对象(也就是实现类)和指定的类型匹配才会拦截,匹配的是目标对象

args

匹配方法中的参数

匹配只有一个参数,且类型为com.example.lx.pojo.User

@Pointcut("args(com.example.lx.pojo.User)")

匹配多个参数

//..表示0个或者多个参数
@Pointcut("args(com.example.lx.pojo.User, ..)")

@target

匹配的目标对象的类有一个指定的注解

目标对象类注解上有指定注解,调用该目标对象的任意方法都会被拦截

@Pointcut("@target(com.example.lx.MyAnnotation)")

示列
UserService 类的所有方法调用都会被拦截

@MyAnnotation
public class UserService {
	public void method() {
	}
}

@args

方法参数所属的类型类上有指定的注解
注意:是方法参数所属类型对应的类上面有指定的注解,不是方法参数中有注解

匹配一个参数,且参数对应类型类上有指定注解

@Pointcut("@args(com.example.lx.MyAnnotation)")

示列

@MyAnnotation
public class User {
}
//User类上有@MyAnnotation注解,所以会被拦截
public void test(User user) {
      
}

匹配多个参数,且多个参数所属类型上都有对应的注解

//第一个参数类型有注解MyAnnotation, 第二个参数类型有注解MyAnnotation2
@Pointcut("@args(com.example.lx.MyAnnotation, com.example.lx.MyAnnotation2)")

匹配多个参数,只要求第一个参数所属类型有对应注解

@Pointcut("@args(com.example.lx.MyAnnotation, ..")

@within

拦截方法对应类有指定类注解的方法

@Pointcut("@within(com.example.lx.MyAnnotation")

示列
UserService 类的所有方法调用都会被拦截

@MyAnnotation
public class UserService {
	public void method() {
	}
}

@target 和 @within 的不同

  1. @taget(注解A): 判断被调用的目标对象中是否声明了注解A,如果有,被拦截
  2. @within(注解A): 判断被调用的方法所属的类中声明了注解A,如果有,被拦截
  3. @target关注的是被调用的对象,@within关注的是调用的方法所在类

@annotation

匹配有指定注解的方法(注解作用在方法上面)

被调用的方法包含指定的注解MyAnnotation

@Pointcut("@annotation(com.example.lx.MyAnnotation")

bean

当调用的方法是指定的bean的方法时生效
spring aop自增

匹配id或者名字是userService的bean中所有方法

@Pointcut("bean(userService")

匹配id或者名字是user开头的bean中所有方法

@Pointcut("bean(user*)")

通知

@Pointcut

切入点,和其他通知注解结合使用

支持的操作符

  • &&:与操作符
  • ||:或操作符
  • !:非操作符

@Pointcut("execution(* com.fsx.run.MessageSender.*(..))")
private void logSender(){}

@Pointcut("execution(* com.fsx.run.MessageReceiver.*(..))")
private void logReceiver(){}

//等同于上面两个方法一起
@Pointcut("logSender() || logReceiver()")
private void logMessage(){}

@Pointcut("execution(* com.abc.service.*.access*(..)) && args(String)")
private void logMessage(){}

@Before

前置增强,相当于BeforeAdvice,目标方法执行前执行

@Before("execution(* com.abc.service.*.many*(..))")
public void permissionCheck(JoinPoint point) {
    System.out.println("@Before:目标方法为:" + 
            point.getSignature().getDeclaringTypeName() + 
            "." + point.getSignature().getName());
    System.out.println("@Before:参数为:" + Arrays.toString(point.getArgs()));
    System.out.println("@Before:被织入的目标对象为:" + point.getTarget());
}
//写法二:
@Pointcut("execution(execution(* com.abc.service.*.many*(..))")
private void pointcut() {
    log.info("pointcut");
}
@Before(value = "pointcut()")
public void before(JoinPoint point) {
    log.info("before");
}

@After

final增强,不管是抛出异常或者正常退出都会执行

@After("execution(* com.abc.service.*.many*(..))")
public void releaseResource(JoinPoint point) {
    System.out.println("@After:目标方法为:" + 
            point.getSignature().getDeclaringTypeName() + 
            "." + point.getSignature().getName());
    System.out.println("@After:参数为:" + Arrays.toString(point.getArgs()));
    System.out.println("@After:被织入的目标对象为:" + point.getTarget());
}
//写法二:
@Pointcut("execution(execution(* com.abc.service.*.many*(..))")
private void pointcut() {
    log.info("pointcut");
}
@After(value = "pointcut()")
public void after(JoinPoint point) {
    log.info("after");
}

@AfterReturning

后置增强,相当于AfterReturningAdvice,方法正常退出时执行

@AfterReturning(pointcut="execution(* com.abc.service.*.many*(..))", 
    returning="returnValue")
public void log(JoinPoint point, Object returnValue) {
    System.out.println("@AfterReturning:目标方法为:" + 
            point.getSignature().getDeclaringTypeName() + 
            "." + point.getSignature().getName());
    System.out.println("@AfterReturning:参数为:" + 
            Arrays.toString(point.getArgs()));
    System.out.println("@AfterReturning:返回值为:" + returnValue);
    System.out.println("@AfterReturning:被织入的目标对象为:" + point.getTarget());
}
//写法二:
@Pointcut("execution(execution(* com.abc.service.*.many*(..))")
private void pointcut() {
    log.info("pointcut");
}
@AfterReturning(value = "pointcut()")
public void afterReturning(JoinPoint point, Object returnValue) {
    log.info("afterReturning");
}

@AfterThrowing

异常抛出增强,相当于ThrowsAdvice,目标方法抛出异常后执行

@AfterThrowing(value = "target(net.deniro.spring4.aspectj.CookA)",throwing = "e")
public void bind(Exception e){
    System.out.println("绑定异常【开始】");
    System.out.println("e:" + e.getMessage());
    System.out.println("绑定异常【结束】");
}
//写法二:
@Pointcut("execution(execution(* com.abc.service.*.many*(..))")
private void pointcut() {
    log.info("pointcut");
}
@AfterThrowing(value = "pointcut()")
public void afterThrowing(Exception e) {
    log.info("afterThrowing");
}    

@Around

环绕增强,相当于MethodInterceptor

@Around("execution(* com.abc.service.*.many*(..))")
public Object process(ProceedingJoinPoint point) throws Throwable {
    //访问目标方法的参数:
    Object[] args = point.getArgs();
    if (args != null && args.length > 0 && args[0].getClass() == String.class) {
        args[0] = "改变后的参数1";
    }
    //用改变后的参数执行目标方法
    Object returnValue = point.proceed(args);
    System.out.println("@Around:执行目标方法之后...");
    System.out.println("@Around:被织入的目标对象为:" + point.getTarget());
    return "原返回值:" + returnValue + ",这是返回结果的后缀";
}
//写法二:
@Pointcut("execution(execution(* com.abc.service.*.many*(..))")
private void pointcut() {
    log.info("pointcut");
}
@Around(value = "pointcut()")
public void around(ProceedingJoinPoint point) {
    log.info("around");
}

@Order

同一个方法被多个Aspect类拦截,通过@Order设置优先级,值越小优先级越高

优先级为1的切面类Bean1包含了@Before,优先级为2的切面类Bean2包含了@Around,虽然@Around优先级高于@Before,但由于Bean1的优先级高于Bean2的优先级,因此Bean1中的@Before先被织入

@Aspect
@Component
@Order(value = 1)
public class Aspect1 {
...
}

@Aspect
@Component
@Order(value = 2)
public class Aspect2 {
...
}

在这里插入图片描述

AspectJ注解和事务注解是在Spring框架中用于声明式事务管理的两种方式。 AspectJ注解是一种通过注解方式来实现面向切面编程的技术。例如,@annotation(org.springframework.transaction.annotation.Transactional)可以用来标注在方法上,表示该方法使用了@Transactional注解来启用事务管理功能。 事务注解是一种用于定义事务相关信息的注解,可以用于指定事务的隔离级别、超时信息、传播行为、是否只读等。同时,事务注解还可以与事务状态(TransactionStatus)一起使用,用于控制事务的提交或回滚等操作。 在Spring框架中,可以通过配置文件或注解方式来实现声明式事务管理。对于AOP XML方式的声明式事务管理,需要配置事务管理器和增强功能,然后在业务层通过配置或注解来启用事务。而对于注解方式的声明式事务管理,只需要配置事务管理器,并在业务层添加相应的注解即可。 总结来说,AspectJ注解和事务注解都是在Spring框架中用于实现声明式事务管理的方式,前者通过注解方式实现面向切面编程,后者用于定义事务相关信息并与事务状态一起使用。可以根据具体需求选择适合的方式来管理事务。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [spring切面的使用@AspectJ注解的3种配置](https://blog.csdn.net/u010010600/article/details/114116528)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [AOP基于AspectJ注解开发和事务JDBC模板](https://blog.csdn.net/qq_42216575/article/details/100809416)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值