这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战
Spring AOP之@AspectJ注解
Spring2.0之后发布的新的特性:
- @AspectJ注解到POJO来定义Aspect以及Advice。
- xml配置的简化,引入aop独有的命名空间方式,来配置aop。
Spring会搜索注解了@AspectJ的类,然后将他们织入系统中。
使用
定义一个Aspect如下:
1 | java复制代码@Aspect |
如何将这个Aspect织入到我们的目标对象中?有2种方式:
编程织入方式
使用AspectJProxyFactory:
1 | java复制代码AspectJProxyFactory weaver = new AspectJProxyFactory(); |
自动代理织入方式
使用AutoProxyCreator:AnnotationAwareAspectJAutoProxyCreator。它会自动收集IOC容器中注册的Aspect,并作用到目标对象上。
只需要在配置文件中注入AnnotationAwareAspectJAutoProxyCreator,spring2.x之后提供了更简单的配置:
1 | xml复制代码<aop:aspectj-autoproxy proxy-target-clas="true"> |
@AspectJ形式的Pointcut
1 | java复制代码@Pointcut("execution(public void *.method1()) || execution(public void *.method2())") |
SpringAOP只集成了AspectJ的Pointcut的部分功能,其中包括Pointcut的语言支持。
@Aspect的pointcut申明方式主要包含2个部分:
- Pointcut Expression
- 真正指定Pointcut的地方。
- 表达式中可以&& || !这些逻辑运算符
- Pointcut Signature
- 需要一个定义的方法做为载体,这个方法必须是void类型
- 如果该方法是public的,那么这个pointcut可以被其他的Aspect引用,如果是private那么只能被当前Aspect类引用。
Aspectj的pointcut表述语言中有很多标志符,但是SpringAOP只能是用少数的几种,因为Spring只对方法级别的pointcut。
- execution
- 规定格式:
execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
- 只有返回类型,方法名,参数模式是必须的,其他的可以省略。
- 这里面我们可以使用2种通配符
*
匹配任意的意思..
当前包以及子包里面所有的类
- 规定格式:
- within
- 只接受类型的声明,会匹配指定类型下面所有的Jointpoint。对SpringAOP来说及,匹配这个类下面所有的方法。
- this和target
- this指代方法调用方,target指被调用方。
- this(o1) && this(o2) 即表示当o1类型对象,调用o2类型对象的方法的时候,才会匹配。
- args
- 指定参数的类型,当调用方法的参数类型匹配就会捕捉到。
- @within
- 指定某些注解,如果某些类上面有指定的注解,那么这个类里面所有的方法都将被匹配。
- @target
- 目标类是指定注解的时候,就会被匹配,SpringAOP中和@within没什么区别,只不过@within是静态匹配,@target是运行时动态匹配。
- @args
- 如果传入的参数的类型 有其指定的注解类型,那么就被匹配。
- @annotation
- 系统中所有的对象的类方法中,有注解了指定注解的方法,都会被匹配。
这些注解的pointcut在spring内部最终都会转为具体的pointcut对象。
@AspectJ形式的Advice
主要就是一些Advice的注解:
- @Before
- 想要获取方法的参数等信息:可以2种方法
- 第一个参数设置为JoinPoint,这个参数必须要放在第一个位置,并且除了Around Advice和Introduction不可以用它,其他的Advice都可以使用。
- args标志符绑定(不常用)
- 想要获取方法的参数等信息:可以2种方法
- @AfterReturning
- 有一个独特属性:returning,可以获取到方法返回值。
- @AfterThrowing
- 有一个独特属性:throwing 可以接受抛出的异常对象。
- @After(也叫finally)
- 一般做资源的释放工作的
- @Around
- 它的第一个参数必须是ProceedingJoinPoint类型,且必须指定。通过ProceedingJoinPoint的proceed()方法执行原方法的调用。
- proceed()方法需要传入参数,则传入一个Object[]数组。
- @DeclareParents
- 处理Introduction的,不多描述了。
其他
advice的执行顺序
- 如果这些advice都在一个aspect类里面:
相同的advice按照申明顺序做优先级,但是注意一点,BeforeAdvice先申明优先级高,则先执行。而AfterReturningAdvice则是先申明优先级高,但是优先级高的越后执行。
1 | erlang复制代码before1 |
- 如果这些Advice在不同的Aspect里面:
借助于Ordered接口,否则Advice的执行顺序是无法确定的。
Aspect的实例化模式
有3种:singleton,perthis,pertarget。(不太重要)
本文转载自: 掘金