前置通知
在 Spring 中启用 AspectJ 注解支持
要在 Spring 应用中使用 AspectJ 注解, 必须在 classpath 下包含 AspectJ 类库: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
将 aop Schema 添加到 <beans> 根元素中.
要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素 <aop:aspectj-autoproxy>
当 Spring IOC 容器侦测到 Bean 配置文件中的 <aop:aspectj-autoproxy> 元素时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理.
用 AspectJ 注解声明切面
要在 Spring 中声明 AspectJ 切面, 只需要在 IOC 容器中将切面声明为 Bean 实例. 当在 Spring IOC 容器中初始化 AspectJ 切面之后, Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理.
在 AspectJ 注解中, 切面只是一个带有 @Aspect 注解的 Java 类.
通知是标注有某种注解的简单的 Java 方法.
AspectJ 支持 5 种类型的通知注解:
@Before: 前置通知, 在方法执行之前执行
@After: 后置通知, 在方法执行之后执行
@AfterReturning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@Around: 环绕通知, 围绕着方法执行
前置通知
前置通知:在方法执行之前执行的通知
前置通知使用 @Before 注解, 并将切入点表达式的值作为注解值.
利用方法签名编写 AspectJ 切入点表达式
最典型的切入点表达式时根据方法的签名来匹配各种方法:
execution * com.atguigu.spring.ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 中声明的所有方法,第一个 * 代表任意修饰符及任意返回值. 第二个 * 代表任意方法. .. 匹配任意数量的参数. 若目标类与接口与该切面在同一个包中, 可以省略包名.
execution public * ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 接口的所有公有方法.
execution public double ArithmeticCalculator.*(..): 匹配 ArithmeticCalculator 中返回 double 类型数值的方法
execution public double ArithmeticCalculator.*(double, ..): 匹配第一个参数为 double 类型的方法, .. 匹配任意数量任意类型的参数
execution public double ArithmeticCalculator.*(double, double): 匹配参数类型为 double, double 类型的方法.
合并切入点表达式
在 AspectJ 中, 切入点表达式可以通过操作符 &&, ||, ! 结合起来.
让通知访问当前连接点的细节
可以在通知方法中声明一个类型为 JoinPoint 的参数. 然后就能访问链接细节. 如方法名称和参数值.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.learn.spring.aspectJ"></context:component-
scan>
<!-- 基于注解开发开启aop自动代理-->
<aop:aspectj-autoproxy/>
</beans>
package com.learn.spring.aspectJ;
public interface ArithmeticCalculator {
public int add(int i, int j );
public int sub(int i, int j );
public int mul(int i, int j );
public int div(int i, int j );
}
package com.learn.spring.aspectJ;
import org.springframework.stereotype.Component;
@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j ;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j ;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j ;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j ;
return result;
}
}
package com.learn.spring.aspectJ;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 日志切面
*/
@Component //标识为组件
@Aspect //标识为切面
@Order(3) //指定切面的优先级. 值越小,优先级越高. 标注@Order的切面比不标注@Order切面的优先级高
public class LoggingAspect {
/**
* 通知: 前置 后置 返回 异常 环绕
*/
/**
* 前置通知: 在方法执行之前执行.
* JoinPoint:连接点对象 包含了连接点相关的信息:方法名 方法的参数等....
*/
//@Before("execution(public int com.learn.spring.aspectJ.ArithmeticCalculator.add(int,int))")
//@Before("execution(public int com.learn.spring.aspectJ.ArithmeticCalculator.*(int,int))")
//任意修饰符任意返回值 com.learn.spring.aspectJ包下的任意类的任意方法 任意参数
//@Before("execution(* com.learn.spring.aspectJ.*.*(..))")
@Before("suibian()")
public void beforeMethod(JoinPoint joinPoint){
//获取方法名:
String methodName = joinPoint.getSignature().getName();
//获取参数
Object [] args = joinPoint.getArgs();
System.out.println("The method "+methodName+" begins with "+ Arrays.asList(args));
}
}
package com.learn.spring.aspectJ;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("spring-aspectJ.xml");
ArithmeticCalculator ac =
(ArithmeticCalculator)ctx.getBean("arithmeticCalculatorImpl");
System.out.println(ac.getClass().getName());
int result = ac.div(2, 1);
System.out.println("AspectJ-result====>:"+result);
}
}