「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」
前言:书接上文,上篇说完了aop的技术点,今天我们来看一下他的代码实现。
介绍:在上文我们说到Spring2.0后是可以使用基于 AspectJ 注解或者XML来编写的。
基于 AspectJ 注解来完成AOP。
- 切入点表达式的用法多样,各种写法都对应这不通的情况,介绍如下:
- execution(public void com.aop.HelloWorld()) :匹配aop中返回值为void且无参数的HelloWorld方法
- execution(public void com.aop.*()) :匹配aop中返回值为void且无参数的所有public方法
- execution(public void com.aop.*(..)) :匹配aop中返回值为void的所有public方法
- execution(public * com.aop.*(..)) :匹配aop中所有public方法
- 代码实现
// 声明该方法为前置通知
@Before("execution(public void com.aop.demo.HelloWorld()) || execution(public void com.aop.demo.HelloWorlds(String))")
public void beforeMethod(JoinPoint point) {
String methodName = point.getSignature().getName();
System.out.println("如果访问com.aop.demo.HelloWorld方法或者访问com.aop.demo.HelloWorld(String)方法 beforeMethod: " + methodName);
}
// 后置通知,无论该方法是否发生异常
@After("execution(public void com.aop.demo.*())")
public void endMethod(JoinPoint point) {
String methodName = point.getSignature().getName();
System.out.println("如果访问com.aop.demo下的所有方法 endMethod: " + methodName);
}
// 返回通知,正常返回时的通知,不包括异常,可以访问到方法的方绘制
@AfterReturning(value = "execution(public void com.aop.demo.*())", returning = "result")
public void afterReturning(JoinPoint point, Object result) {
String methodName = point.getSignature().getName();
System.out.println("AfterReturning : " + methodName + ", result: " + result);
}
// 异常通知
@AfterThrowing(value = "execution(public void com.aop.demo.*())", throwing = "ex")
public void afterThrowing(JoinPoint point) {
String methodName = point.getSignature().getName();
System.out.println("AfterThrowing : " + methodName);
}
// 环绕通知
@Around("execution(public void com.aop.demo.*())")
public void aroundMethod(ProceedingJoinPoint point,MyAnnotation around) throws Throwable{
// 环绕通知(前通知)
System.out.println("开始...");
System.out.println("调用方法:"+ around.methodName());
System.out.println("调用类:" + point.getSignature().getDeclaringTypeName());
System.out.println("调用类名" + point.getSignature().getDeclaringType().getSimpleName());
try {
// 前置通知
point.proceed(); // 目标方法执行
} catch (Throwable throwable) {
// 异常通知
throwable.printStackTrace();
}
// 环绕通知(后通知)
System.out.println("结束...");
}
基于web.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance http://www.springmodules.org/schema/cache/springmodules-cache.xsd http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- 配置目标类id -->
<bean id="helloWorldService" class="com.aop.demo"/>
<!-- 配置切面id -->
<bean id="aspect" class="com.aop.demo"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.aop..*.*(..))"/>
<!-- aop:aspect的ref引用切面支持类的方法 -->
<aop:aspect ref="aspect">
<aop:before pointcut-ref="pointcut"
method="beforeAdvice"/>
<aop:after pointcut-ref="pointcut"
method="afterAdvice"/>
</aop:aspect>
</aop:config>
</beans>
</web-app>
切入点使用<aop:config>标签下的<aop:pointcut>配置,expression属性用于定义切入点模式,默认是AspectJ语法,"execution(* com.aop...(..))"表示匹配com.aop包下及子包下的任何方法执行。 切面使用<aop:config>标签下的<aop:aspect>标签配置,其中"ref"用来引用切面支持类的方法。
前置通知<aop:before>标签,pointcut-ref属性用于引用切入点Bean,而method用来引用切面通知实现类中的方法,该方法就是通知实现,即在目标类方法执行之前调用的方法。
后置通知<aop:after>标签,切入点除了使用pointcut-ref属性来引用已经存在的切入点,也可以使用pointcut属性来定义,如pointcut="execution(* com.aop...(..))",method属性同样是指定通知实现,即在目标类方法执行之后调用的方法。