Java中基于Spring注解实现AOP增强方法

demo

@Aspect
@Component
public class LoginLogAspect {


    @Pointcut("execution(public * com.test.sg.service.impl.LoginServiceImpl.login(..))")
    public void login() {
    }


    @AfterThrowing("login()")
    public void loginFail(JoinPoint joinPoint) {
        // fail
        // 从切点获取方法的参数
        Object[] args = joinPoint.getArgs();
    }

    @AfterReturning("login()")
    public void loginSuccess(JoinPoint joinPoint) {
        // success
        // 从切点获取方法的参数
        Object[] args = joinPoint.getArgs();
    }
}

对com.test.sg.service.impl.LoginServiceImpl包下的login方法进行增强,
如果抛出异常,则认为登录失败,
如果没有异常,则认为登录成功
方法中可以进行具体的操作

相关注解

@Aspect

申明切面类

@Component

将类交给spring管理

@Pointcut

申明切点

参数格式:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
括号中各个pattern分别表示:

  • 修饰符匹配(modifier-pattern?)
  • 返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等
  • 类路径匹配(declaring-type-pattern?)
  • 方法名匹配(name-pattern)可以指定方法名 或者 代表所有, set 代表以set开头的所有方法
  • 参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用“”来表示匹配任意类型的参数,如(String)表示匹配一个String参数的方法;(,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型;可以用(…)表示零个或多个任意参数
  • 异常类型匹配(throws-pattern?)
  • 其中后面跟着“?”的是可选项

示例:

1)execution(* *(..))  
//表示匹配所有方法  
2)execution(public * com. test.service.UserService.*(..))  
//表示匹配com.test.server.UserService中所有的公有方法  
3)execution(* com.test.server..*.*(..))  
//表示匹配com.test.server包及其子包下的所有方法 

不同写法

 @Pointcut("execution(public * com.test.sg.service.impl.LoginServiceImpl.login(..))")
    public void login() {
    }

 @AfterThrowing("login()")//如果login()不在一个类中,可以使用全名
 public void loginFail(JoinPoint joinPoint) {
 }

等同于=====

@AfterThrowing("execution(public * com.test.sg.service.impl.LoginServiceImpl.login(..))")
public void loginFail(JoinPoint joinPoint) {
}

可以使用&&,||,!

@Pointcut("execution(public * com.test.service.impl.LoginServiceImpl.login(..)) " +
            "|| execution(public * com.test.service.impl.LoginServiceImpl.test2(..))")
public void login() {
}

表示匹配com.test.service.impl.LoginServiceImpl包中的login或者test2方法

@Order

如果有需要,可以指定AOP的执行顺序,数值越小越先执行,取值范围是int的范围,默认是int的最大值

执行顺序

该段落原文链接:https://blog.csdn.net/zhanglf02/article/details/78132304

  • @Before 前置通知(Before advice) :在某连接点(JoinPoint)——核心代码(类或者方法)之前执行的通知,但这个通知不能阻止连接点前的执行。为啥不能阻止线程进入核心代码呢?因为@Before注解的方法入参不能传ProceedingJoinPoint,而只能传入JoinPoint。要知道从aop走到核心代码就是通过调用ProceedingJionPoint的proceed()方法。而JoinPoint没有这个方法。
    这里牵扯区别这两个类:Proceedingjoinpoint 继承了 JoinPoint 。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。暴露出这个方法,就能支持 aop:around 这种切面(而其他的几种切面只需要用到JoinPoint,这跟切面类型有关), 能决定是否走代理链还是走自己拦截的其他逻辑。建议看一下 JdkDynamicAopProxy的invoke方法,了解一下代理链的执行原理。这样你就能明白 proceed方法的重要性。

  • @After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

  • @AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。

  • @Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。这时aop的最重要的,最常用的注解。用这个注解的方法入参传的是ProceedingJionPoint pjp,可以决定当前线程能否进入核心方法中——通过调用pjp.proceed();

  • @AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。

针对一个方法只被一个aspect类拦截时,aspect类内部的 advice 将按照以下的顺序进行执行情况如下:
正常返回就走@AfterReturn,有异常就走@AfterThrowing
在这里插入图片描述
在这里插入图片描述

JoinPoint和ProceedingJoinPoint

AspectJ使用org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用org.aspectj.lang.ProceedingJoinPoint表示连接点对象,该类是JoinPoint的子接口。任何一个增强方法都可以通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。我们先来了解一下这两个接口的主要方法:
1)JoinPoint
java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
Signature getSignature() :获取连接点的方法签名对象;
java.lang.Object getTarget() :获取连接点所在的目标对象;
java.lang.Object getThis() :获取代理对象本身;
2)ProceedingJoinPoint
ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法:
java.lang.Object proceed() throws java.lang.Throwable:通过反射执行目标对象的连接点处的方法;
java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参。

发布了37 篇原创文章 · 获赞 1 · 访问量 1065

猜你喜欢

转载自blog.csdn.net/zhuchencn/article/details/102542222
今日推荐