要在 Spring 中声明 AspectJ 切面, 只需要在 IOC 容器中将切面声明为 Bean 实例. 当在 Spring IOC 容器中初始化 AspectJ 切面之后, Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理,AOP的原理其实就是利用了动态代理,将动态代理进行了封装。
在 AspectJ 注解中, 切面 只是一个带有 @Aspect 注解的 Java 类,通知 则是标注有某种注解的简单的 Java 方法。
AspectJ 支持 5 种类型的通知注解:
@Before: 前置通知, 在方法执行之前执行
@After: 后置通知, 在方法执行之后执行
@AfterRunning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@Around: 环绕通知, 围绕着方法执行
前置通知
前置通知:在目标 方法开始之前进行执行的通知。
前置通知使用 @Before 注解, 并将 切入点表达式的值作为注解值。
value属性值:切入点表达式,匹配与之对应的目标。利用【】可以进行那匹配不同的目标,参数只需要传入类型即可。
方法体* JoinPoint 参数:用来连接当前连接点的连接细节,一般包括方法名和参数值。【org.aspectj.lang.JoinPoint】包
@Before( value="execution(public int com.wf.springaopImpl.ArithmeticCalculatorImpl.*(int , int))")
public void brforelogging(JoinPoint joinPoint){ //注意 JoinPoint 的包
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("The brforelogging methor"+ methodName+" begin with"+args);
}
后置通知
后置通知: 在目标方法执行之后,无论是否发生异常,都进行执行的通知。
后置通知使用@After注解, 并将切入点表达式的值作为注解值。
在后置通知中,不能访问目标方法的执行结果。原因可能在执行过程中发生异常而无法得到结果。
// @After("execution(public int com.wf.springaopImpl.ArithmeticCalculatorImpl.*(int , int)))")
public void afterlogging(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("The afterlogging method "+methodName+" end");
}
返回通知
返回通知: 在目标方法 正常结束时,才执行的通知
返回通知使用@AfterReturning注解,并将切入点表达式的值作为注解值。
返回通知可以访问到方法的返回值。
returning属性值: 声明该方法可以存在返回值,该属性的值即为用来传入返回值的参数名称。
方法体Object参数 : 需要使用与returning同名参数名称,用来接收方法的返回值。
@AfterReturning(value="execution(public int com.wf.springaopImpl.ArithmeticCalculatorImpl.*(int , int)))",returning="result")
public void afterreturninglogging(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("The afterreturninglogging method "+methodName+" end with "+result);
}
异常通知
异常通知 :在目标方法出现异常时才会进行执行的代码。
异常通知使用@AfterThrowing注解,并将切入点表达式的值作为注解值。
throwing属性: 访问连接点抛出的异常。
方法体Exception参数: 用来接收连接点抛出的异常。Exception类匹配所有的异常,可以指定为特定的异常 例如NullPointerException类等
@AfterThrowing(value="execution(public int com.wf.springaopImpl.ArithmeticCalculatorImpl.*(int , int)))",throwing="ex")
public void afterthrowinglogging(JoinPoint joinPoint, Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("The afterthrowinglogging method "+methodName+" occurs excetion: "+ex);
}
环绕通知
环绕通知是所有通知类型中功能最为强大的, 能够全面地控制连接点。甚至可以控制是否执行连接点。类似于动态代理。
环绕通知 连接点的参数类型必须是 ProceedingJoinPoint ,它是 JoinPoint 的子接口,,允许控制何时执行, 是否执行连接点。
环绕通知中需要明确调用 ProceedingJoinPoint 的 proceed() 方法来执行被代理的方法,如果忘记这样做就会导致通知被执行了,但目标方法没有被执行。
环绕通知的方法需要有返回值,返回目标方法执行之后的结果, 即调用 joinPoint.proceed() 的返回值, 否则会出现空指针异常。
环绕通知虽然功能最为强大的,但是一般我们都不使用这个。
@Around(value="execution(public int com.wf.springaopImpl.ArithmeticCalculatorImpl.*(int , int)))")
public Object aroundlogging(ProceedingJoinPoint pjd){
Object result =null;
String methodName = pjd.getSignature().getName();
List<Object> args = Arrays.asList(pjd.getArgs());
try {
// 前置通知
System.out.println("The aroundlogging methor"+ methodName+" begin with"+args);
result = pjd.proceed();
// 返回通知
System.out.println("The aroundlogging method "+methodName+" end with "+result);
} catch (Throwable e) {
System.out.println("The aroundlogging method "+methodName+" occurs excetion: "+e);
// 异常通知
e.printStackTrace();
}
//后置通知
System.out.println("The aroundlogging method "+methodName+" end");
return result;
}
切入点表达式
在切入点表达式中我们可以利用【*】去进行模糊匹配。
最典型的就是下面的这个,我们可以根据这个进行一系列的变形。
execution(* com.wf.springaopImpl.ArithmeticCalculatorImpl.*(..))
//第一个 * 代表任意修饰符及任意返回值. 第二个 * 代表任意方法. .. 匹配任意数量的参数.
//若目标类与接口与该切面在同一个包中, 可以省略包名.
execution(public * ArithmeticCalculator.*(..))
// 匹配 ArithmeticCalculator 接口的所有公有方法.
execution (public double ArithmeticCalculator.*(..))
//匹配 ArithmeticCalculator 中返回 double 类型数值的方法
execution (public double ArithmeticCalculator.*(double, ..))
// 匹配第一个参数为 double 类型的方法, .. 匹配任意数量任意类型的参数
切面优先级
当在同一个方法中存在多个切面时,我们可以在注解切面的类中添加新的注解@Order,可以给我们的切面进行优先级排序,@Order(index) 其中index的值越小,所对应的优先级就越高。
重用切点表达式
有时候一个切点可以有多个通知,就像上面,如果我们将切点表达式写在每一个通知中,会有大量的重复代码。因此我们可以重用切点表达式。
// 定义一个方法,利用注解@Pointcut用于声明切入点达式,然后在其中引入方法名即可。
// 我们可以利用ValidateAspect.declareJoinPointExpression()进行跨类声明【类名.方法名】。
// 甚至我们可以利用【类的全路径.方法名】使切点表达式作用于不同的包中。
public class ValidateAspect {
@Pointcut(value="execution(public int com.wf.springaopImpl.ArithmeticCalculatorImpl.*(int , int))")
public void declareJoinPointExpression(){
}
@Before("declareJoinPointExpression()")
public void brforeValidate(JoinPoint joinPoint){ //注意 JoinPoint 的包
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("----------The Validate methor"+ methodName+" begin with"+args);
}
@After("declareJoinPointExpression()")
public void afterValidate(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("The afterValidate method "+methodName+" end");
}
}
基于xml的配置通知
对于没有注解的,我们可以将对于切面的相关配置写在我们的配置文件中。具体如下:
1、配置基本bean
2、配置切面bean
3、配置AOP
在配置AOP时,我们进行属性配置
A、配置切面表达式
B、配置切面以及通知
注意:记得要引入aop命名空间。
<!-- 配置基本bean -->
<bean id="arithmeticCalculator" class="com.wf.springaopImplxml.ArithmeticCalculatorImpl"></bean>
<!-- 配置切面bean -->
<bean id="loggingAspect" class="com.wf.springaopImplxml.LoggingAspect"></bean>
<bean id="validateAspect" class="com.wf.springaopImplxml.ValidateAspect"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(public int com.wf.springaopImplxml.ArithmeticCalculatorImpl.*(int , int))"
id="pointcut"/>
<!-- 配置切面及通知 -->
<aop:aspect ref="loggingAspect" order="2">
<aop:before method="brforelogging" pointcut-ref="pointcut"/>
<aop:after method="afterlogging" pointcut-ref="pointcut"/>
<aop:after-returning method="afterreturninglogging" pointcut-ref="pointcut" returning="result"/>
<aop:after-throwing method="afterthrowinglogging" pointcut-ref="pointcut" throwing="ex"/>
<!-- <aop:around method="aroundlogging" pointcut-ref="pointcut"/> -->
</aop:aspect>
<!-- 配置切面及通知 -->
<aop:aspect ref="validateAspect" order="0">
<aop:before method="brforeValidate" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
[
](https://blog.csdn.net/sinat_28978689/article/details/62215513)