AspectJ形式AOP使用
本文相关代码(来自官方源码spring-test模块)请参见spring-framework org.springframework.mylearntest包下。
无需像1.0那样实现 相应的接口,唯一要做的就是在这个Aspect类上加一个@Aspect注解。这样就可以判断ClassPath中哪些类是我们要找的Aspect定义。通过@Pointcut定义Pointcut,通过Around等注解来指定哪些方法定义了相应的Advice逻辑。
PerformanceTraceAspect
package org.springframework.mylearntest.aop2.aspectj;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* @Author: whalefall
* @Date: 2020/7/28 22:46
* Spring 2.0 之后无需实现接口定义pointcut
*/
@Aspect
public class PerformanceTraceAspect {
private final Log logger = LogFactory.getLog(PerformanceTraceAspect.class);
@Pointcut("execution(public void *.method1()) || execution(public void *.method2())")
public void pointcutName() {}
@Around("pointcutName()")
public Object performanceTrace(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch sw = new StopWatch();
try {
sw.start();
return joinPoint.proceed();
} finally {
System.out.println("pt in method["
+ joinPoint.getSignature().getName()
+ "]>>>>>>" + sw.toString());
}
}
}
两种织入Aspect方法
假如我们有一个目标对象Foo,有两种方式将Aspect定义织入这个目标对象类,,实现对其符合Pointcut定义的Joinpoint进行拦截。
Foo
public class Foo {
public void method1() {
System.out.println("method1 executed");
}
public void method2() {
System.out.println("method2 executed");
}
}
编程方式织入
通过AspectJProxyFactory实现
public class Test4AspectJProxyFactory {
public static void main(String[] args) {
AspectJProxyFactory weaver = new AspectJProxyFactory();
weaver.setProxyTargetClass(true);
weaver.setTarget(new Foo());
weaver.addAspect(PerformanceTraceAspect.class);
Object proxy = weaver.getProxy();
((Foo)proxy).method1();
((Foo)proxy).method2();
}
}
通过自动代理织入
针对@AspectJ风格的AOP,Spring AOP专门提供了一个AutoProxyCreator实现类进行自动代理,以免去过多的编码和配置工作,它是在AbstractAdvisorAutoProxyCreator基础上的一个扩展类。
与AutoProxyCreator一样,我们需要在IoC容器的配置文件中注册一下AnnotationAwareAspectJAutoProxyCreator就可以了。
xml 配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 等同于上面一行-->
<!--<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
<property name="proxyTargetClass" value="true"/>
</bean>-->
<bean id="performanceAspect" class="org.springframework.mylearntest.aop2.aspectj.PerformanceTraceAspect"/>
<bean id="target" class="org.springframework.mylearntest.aop2.aspectj.Foo"/>
</beans>
TestAutoAspectJ
public class Test4AutoAspectJ {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("annotationawareaspectJautoproxycreator\\annotationawareaspectJautoproxycreator.xml");
Object proxy = context.getBean("target");
((Foo)proxy).method1();
((Foo)proxy).method2();
}
}
如果把target作为依赖对象注入其他的bean定义,那么依赖的主体对象在持有的也是被代理过的目标对象。
Tip
在使用@AspectJ形式的AOP的时候,应该尽量使用容器内的自动代理支持,通常,只有处于测试目的才会使用编程的方式直接织入操作,在使用过程中,你会发现,实际上这两种方式是有差异的,一些行为并不统一。
使用@Aspect形式的AOP,需要引入aspectjweaver.jar和aspectjrt.jar。
@AspectJ形式的Pointcut
在Spring框架发布 2.0 版本之前,Spring AOP没有像AspectJ那样的正式的Pointcut描述语言,而且也只支持方法级别的拦截。所以通常情况下,简单的方法名 指定以及正则表达式两种,基本上可以很好地达到目的。
在Spring发布 2.0 版本之后,Spring AOP 框架集成了AspectJ的部分功能,这其中就包括AspectJ的Pointcut语言支持。从DTD过渡到XSD时代。
@AspectJ形式Pointcut声明方式
@AspectJ形式的Pointcut声明,依附在@ApectJ,通过使用org.aspectj.lang.annotation.Pointcut这个注解,指定AspectJ形式的Pointcut 表达式之后,将这个指定了相应表达式的注解标注到Aspect定义类的某个方法上即可。
@AspectJ形式的Pointcut声明包含如下两个部分。
- Pointcut Expression
Pointcut Expression的载体为@Pointcut,该注解是方法级别的注解,所以Pointcut Expression不能脱离某个方法单独声明
表达式由两部分组成,分别是Pointcut标识符,和表达式匹配模式。
- Pointcut Signature
它是一个方法的定义,作为Pointcut Expression的载体。Pointcut Signature所在的方法定义,除了返回类型必须是void之外,没有其他的限制。方法修饰符所起到的作用于java语言中语义相同,public型的Pointcut Signature可以在其他Aspect定义中引用,private则只能在当前Aspect定义中引用。可以将Pointcut Signature作为相应Pointcut Expression的标识符,在Pointcut Expression的定义中取代重复的Pointcut表达式定义。
YourAspect
@Aspect
public class YourAspect {
@Pointcut("execution(void method1())")
public void method1Execution() {}
@Pointcut("method1Execution()")
private void stillMethod1Execution() {}
// ...
}