首页 > 编程语言 >@Aspect

@Aspect

时间:2024-02-21 10:35:29浏览次数:27  
标签:pattern void class Aspect execution type public

一、简介

依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.1.9.RELEASE</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.1.9.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

拦截器:

@Aspect
@Component
public class SomeInterceptor {

将拦截器注册到工厂:

<context:component-scan base-package="yourpackage"></context:component-scan>

开启代理(false 对应 jdk 动态代理,true 对应 cglib 动态代理):

<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>

 二、pointcut

execution - for matching method execution join points, this is the primary pointcut designator you will use when working with Spring AOP
within - limits matching to join points within certain types (simply the execution of a method declared within a matching type when using Spring AOP) 
this - limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type
target - limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type
args - limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types ②
@target - limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type
@args - limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s)
@within - limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)
@annotation - limits matching to join points where the subject of the join point (method being executed in Spring AOP) has the given annotation

 

  • ① 是最主要切面工具,excution 针对方法签名,within 针对类名
  • ②是在①的前提下辅助获取特定信息,比如代理对象(this)、被代理对象(target)、入参(args)、类注解(@within)、方法注解(@annotation)、入参注解(@args) 
  • 当然只有②时相当于①是所有方法
  • 见最后对各个概念的理解

 

 

1. execution

syntax:

execution(modifiers-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: 异常

简版:

execution(ret-type-pattern name-pattern(param-pattern))

详细:

All parts except the returning type pattern (ret-type-pattern in the snippet above), name pattern, and parameters pattern are optional. 
The returning type pattern determines what the return type of the method must be in order for a join point to be matched. 
Most frequently you will use * as the returning type pattern, which matches any return type. 
A fully-qualified type name will match only when the method returns the given type. 
The name pattern matches the method name. 
You can use the * wildcard as all or part of a name pattern. 
If specifying a declaring type pattern then include a trailing . to join it to the name pattern component. 
The parameters pattern is slightly more complex: () matches a method that takes no parameters, whereas (..) matches any number of parameters (zero or more). 
The pattern (*) matches a method taking one parameter of any type, (*,String) matches a method taking two parameters, the first can be of any type, the second must be a String.

 示例:

@Aspect
@Component
public class SomeInterceptor {

    @Pointcut("execution(* doTask*(..))")
    public void methodsToBeProfiled() {
    }

    @Around("methodsToBeProfiled()")
    public void profile(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println(pjp.getSignature().getName());
    }
}

 

2. within

 syntax:

 with(declaring-type-pattern)

如下图,with 是匹配类的全限定名,不是匹配方法

 

示例:

@Aspect
@Component
public class SomeInterceptor {

    @Pointcut("within(cn.zno..*)")
    public void methodsToBeProfiled() {
    }

    @Around("methodsToBeProfiled()")
    public void profile(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println(pjp.getSignature().getName());
    }
}

 

 3. this

syntax:

this(advice-method's-arg-ref-of-target's-proxy-type)

这个是匹配目标类的代理对象

示例:

@Aspect
@Component
public class SomeInterceptor {

    
    @Before("execution(* doTaskA(..)) && this(s)")
    public void validateAccount(SomeClass s) {
        System.out.println(s.getClass());
    }
    // class cn.zno.testaspect.SomeClass$$EnhancerBySpringCGLIB$$5c6bdbdc
}

 

4. target

syntax:

target(advice-method's-arg-ref-of-target-type)

 这个是匹配目标类的实例,即被代理对象

示例:

@Aspect
@Component
public class SomeInterceptor {

    
    @Before("execution(* doTaskA(..)) && target(s)")
    public void validateAccount(SomeClass s) {
        System.out.println(s.getClass());
    }
    // class cn.zno.testaspect.SomeClass
}

5. args

syntax:

 args(advise-method's-arg-ref-list-of-target-current-method's-arg-type-list)

获取目标对象的正在执行方法的入参列表

 示例:

@Aspect
@Component
public class SomeInterceptor {

    
    @Before("execution(* doTaskA(..)) && args(s,i)")
    public void validateAccount(String s,Integer i) {
        System.out.println(s);
        System.out.println(i);
    }
//    abc
//    123
}

6. @target

syntax:

@target(advise-method's-arg-ref-of-annotation-type-on-target-class)

获取目标类的注解

示例:

@Aspect
@Component
public class SomeInterceptor {

    
    @Before("execution(* doTaskA(..)) && @target(s)")
    public void validateAccount(SomeAnnotation s) {
        System.out.println(s.value());
    }
//    123
}
@Component
@SomeAnnotation("123")
public class SomeClass {

    
    public void doTaskA(String s1,Integer i1) {
        
    }
}

 

7. @args

syntax:

@args(advise-method's-arg-ref-list-of-target's-current-method's-arg's-type's-annotation-type-list)

one-one (第一个入参类有第一个注解类,第二个入参类有第二个注解类,以此类推)

示例:

@SomeAnnotation("111") 
public class Other {

}
@Component
public class SomeClass {
    
    public void doTaskA(Other s1) {
        
    }
}
@Aspect
@Component
public class SomeInterceptor {
    
    @Around("execution(* doTaskA(..)) && @args(s)")
    public void validateAccount(SomeAnnotation s) {
        System.out.println(s.value());// 111
    }
}

 8. @within

syntax:

@within(advise-method's-arg-ref-of-annotation-type-on-target-class)

 和@target 有区别(未做详细调查)

示例:

@Component
@SomeAnnotation("1212")
public class SomeClass {
    
    public void doTaskA(String s1) {
        
    }
}
@Aspect
@Component
public class SomeInterceptor {

    
    @Around("execution(* doTask*(..)) && @within(s)")
    public void validateAccount(SomeAnnotation s) {
        System.out.println(s.value());// 1212
    }
}

9. @annotation

syntax:

@annotation(advise-method's-arg-ref-of-annotation-type-on-target-class-method)

示例:

@Component

public class SomeClass {
    
    @SomeAnnotation("333")
    public void doTaskA(String s1) {
        
    }
}
@Aspect
@Component
public class SomeInterceptor {

    
    @Around("@annotation(s)")
    public void validateAccount(SomeAnnotation s) {
        System.out.println(s.value());// 333
    }
}

 

 

10. combine ( and  or  not)  : &&  ||  !

@Pointcut("execution()")
private void a() {}

@Pointcut("within()")
private void b() {}

@Pointcut("a() && b()")
private void ab() {}

或者

@Pointcut("execution() && within()")
private void ab() {}

 

三、advise(对切面的处理链路)

1. 切面是获取方法集合,advise 是对每一个方法的处理链路,即可以多个advise针对同一个方法。任何一个advise 方法都可以获取 JoinPoint 

    @Around("@annotation(s)")
    public void validateAccount(JoinPoint jp) {
        System.out.println(jp.getSignature());
    }

 

 

2. @Before

    @Before(value="execution(* doTask*(..))")
    public void validateAccount(JoinPoint jp) {
        System.out.println(jp.getSignature());
    }

 

    @AfterReturning

    public Integer doTaskA(String s1,String s2) {
        return new Integer("111");
    }
    @AfterReturning(value="execution(* doTask*(..))",returning="ret")
    public void validateAccount(JoinPoint jp,Object ret) {
        System.out.println(jp.getSignature());
        System.out.println(ret.getClass());
    }

输出:

Integer cn.zno.testaspect.SomeClass.doTaskA(String,String)
class java.lang.Integer

 

    @AfterThrowing

    public Integer doTaskA(String s1,String s2) {
        if(1<2)
            throw new RuntimeException("eee");
        return new Integer("111");
    }
    @AfterThrowing(value="execution(* doTask*(..))",throwing="e")
    public void validateAccount(JoinPoint jp,Exception e) {
        System.out.println(jp.getSignature());
        System.out.println(e.getMessage());
    }

输出:

Integer cn.zno.testaspect.SomeClass.doTaskA(String,String)
eee

问题:如何将异常处理,使其不再往外抛?需参考spring mvc

    @After(finally)

    public Integer doTaskA(String s1,String s2) {
        Integer integer;
        try {
            integer = new Integer("111");
        }finally {
            System.out.println(123);
        }
        return integer;
    }
    @After(value="execution(* doTask*(..))")
    public void validateAccount(JoinPoint jp) {
        System.out.println(jp.getSignature());
    }

结果:

123
Integer cn.zno.testaspect.SomeClass.doTaskA(String,String)

确实在finally 块执行完毕之后才会拦截

    @Around

    public Integer doTaskA(String s1,String s2) {
        Integer integer;
        try {
            integer = new Integer("111");
        }finally {
            System.out.println(123);
        }
        return integer;
    }
    @Around(value="execution(* doTask*(..))")
    public void validateAccount(ProceedingJoinPoint pjp) {
        System.out.println("before");
        try {
            pjp.proceed();
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("after");
    }

结果:

before
123
after

 

四、辅助工具

STS4 -> Window -> show view -> AspectJ-> Cross References

注意:需要运行一次单元测试,对应的advise 才会更新

1. 拦截器中有提示

 

 2. 目标类中有提示

 3. Cross References 有全部的!!(IMPORTANT!!)

 

 五、补充知识点

1. 如何修改入参or返回结果

    @Around("someAdvice()")
    public Object someAdvice(ProceedingJoinPoint pjp) throws Throwable {
        // a. 获取目标方法入参列表
        Object[] args = pjp.getArgs();
        // b. 修改目标入参
        ...
        // c. 传入修改后入参列表并 d.返回目标方法结果 (如果调用无参方法 proceed(); 则使用原有参数列表)
        Object proceed = pjp.proceed(args);
        // e. 修改目标方法返回结果
        ...
        // f. 返回修改后的结果
        return proceed;
    }

 

六、理解

 

标签:pattern,void,class,Aspect,execution,type,public
From: https://www.cnblogs.com/zno2/p/10342135.html

相关文章

  • java aspect 切面怎么获取 POST 数据
    javaaspect切面怎么获取POST数据/***切面*/@Aspect@ComponentpublicclassPostRequestBodyAspect{@Pointcut("execution(*com.example.controller.*.*(..))")publicvoidcontrollerMethods(){}......
  • Spring的Bean后置处理器之AnnotationAwareAspectJAutoProxyCreator
    本文能帮你回答以下几个问题;AnnotationAwareAspectJAutoProxyCreator后置器的作用是什么?SpringAOP自动增强bean是如何实现的。如何在spring上下文添加AnnotationAwareAspectJAutoProxyCreator?如何利用ProxyFactory硬编码实现一个bean的增强?AnnotationAwareAspectJAutoProx......
  • QLabel显示图片,QPixmap.scaled Qt::KeepAspectRatio不起作用
    一、问题描述以及解决办法Qt中QLabel可以显示图片。如下:QLabel*label=newQLabel(this);label->setPixmap(QPixmap)其中QPixmap可以缩放图片Pixmappixmap;pixmap.scaled(QSize(width,height),Qt::KeepAspectRatio);//按比例缩放以适应目标矩形,超出部分会被裁......
  • SpringBoot中使用Aspect实现切面
    相关概念切面(Aspect):首先要理解‘切’字,需要把对象想象成一个立方体,传统的面向对象变成思维,类定义完成之后(封装)。每次实例化一个对象,对类定义中的成员变量赋值,就相当于对这个立方体进行了一个定义,定义完成之后,就等着被使用,等着被回收。面向切面编程则是指,对于一个我们已经封装......
  • 自定义元素宽高比例(aspect-ratio)与 @supports兼容支持和图片裁剪(object-fit)的用法
    1、aspect-ratio宽高比例属性aspect-ratio:1/1;aspect-ratio:16/9;aspect-ratio:0.5;//等同于1/2如下效果将为每个box子元素设置aspect-ratio:3/2,如下图所示: 2、object-fit图片裁剪object-fit:contain;保持宽高比,缩放保持图片完整性。object-fit:cover......
  • Spring系列:基于Spring-AOP和Spring-Aspects实现AOP切面编程
    目录一、概念及相关术语概念相关术语①横切关注点②通知(增强)③切面④目标⑤代理⑥连接点⑦切入点作用二、基于注解的AOP技术说明准备工作创建切面类并配置各种通知切入点表达式语法重用切入点表达式获取通知的相关信息环绕通知切面的优先级三、基于XML的AOP准备工作实现一、概念......
  • 最新Unity DOTS系列之Aspect核心机制分析
    最近DOTS发布了正式的版本,我们来分享一下DOTS里面Aspect机制,方便大家上手学习掌握UnityDOTS开发。Aspect 机制概述当我们使用ECS开发的时候,编写某个功能可能需要某个entity的一些组件,如果我们一个个组件的查询出来,可能参数会写很长。如果我们编写某个功能的时候,需要entity的......
  • Unity DOTS系列之Aspect核心机制分析
      最近DOTS发布了正式的版本,我们来分享一下DOTS里面Aspect机制,方便大家上手学习掌握UnityDOTS开发。Aspect 机制概述当我们使用ECS开发的时候,编写某个功能可能需要某个entity的一些组件,如果我们一个个组件的查询出来,可能参数会写很长。如果我们编写某个功能的时候,需要enti......
  • A Challenge Dataset and Effective Models for Aspect-Based Sentiment Analysis
    摘要基于方面的情感分析(ABSA)由于其广泛的应用,近年来受到了越来越多的关注。在现有的ABSA数据集中,大多数句子只包含一个或多个具有相同情感极性的方面,这使得ABSA任务退化为句子级情感分析。在本文中,我们提出了一个新的大规模多方面多情感(MAMS)数据集,其中每个句子至少包含两个具有不......
  • 什么是切面 Aspect?&Spring通知有哪些类型?
    什么是切面Aspect?切面(Aspect)是面向切面编程(AOP)的核心概念之一。它表示一个模块化的、可重用的关注点,它横跨多个对象,并通过将这些横切关注点(cross-cuttingconcerns)从核心业务逻辑中分离出来,可以实现更好的代码组织和更高的可维护性。在AOP中,切面用于捕获并定义一组横切关注点,这......