Spring中AOP的实现分为两种:
一、Java配置实现
1、通过注解定义拦截规则
2、通过方法路径定义拦截规则
二、XML配置实现
1、通过注解定义拦截规则
2、通过方法路径定义拦截规则
一、Java配置实现
(1)Java配置实现,定义一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAction {
}
(2)定义Target,Target中有部分方法加有注解,凡是加有注解的方法都会被拦截下来,没加注解的方法则不受影响:
@Component
public class MyCalcultor {
@MyAction
public int add(int a, int b) {
System.out.println("add。。。");
return a + b; }
public String sayHello(String name) {
return "hello " + name + " !";
}
}
(3)定义切面,切面包含两个部分:切点+增强(通知)分为五大类
*前置通知、通知在目标方法执行之前
*后置通知、通知在目标方法执行之后
*异常通知、通知在目标方法抛异常执行
*返回通知、通知在目标方法有返回值时执行
*环绕通知、包含了前面四种
@Component
@Aspect
public class LogAspect {
/**
* @param point 参数是指连接点,从这个参数中,可以获取方法名方法参数等信息
* @Before注解表示这是一个前置通知,该通知会在目标方法执行之前执行
*/
@Before("@annotation(MyAction)")
public void before(JoinPoint point) {
String name = point.getSignature().getName();
System.out.println(name + "方法开始执行了...");
}
}
(4)其他四种类型的通知
/**
* 这个类就是切面,该类中的内容包含两大块:切点+通知
*
* @Componet只是将该类注册到Spring容器中
* @Aspect表示该类是一个切面
*/@Component
@Aspect
public class LogAspect {
/**
* @param point 参数是指连接点,从这个参数中,可以获取方法名方法参数等信息
* @Before注解表示这是一个前置通知,该通知会在目标方法执行之前执行
*/
@Before("@annotation(MyAction)")
public void before(JoinPoint point) {
String name = point.getSignature().getName();
System.out.println(name + "方法开始执行了...");
}
/**
* 这是一个后置通知,后置通知在目标方法执行结束后执行
* @param point
*/
@After("@annotation(MyAction)"){
System.out.println(point.getSignature().getName() + "方法执行结束了...");
}
/**
* 这是一个返回通知,可以获取目标方法的返回值
*
* 方法中的参数名和注解中的参数名是对应的,参数值就是目标方法的返回值
*
* 需要注意返回值的类型,返回值的类型必须是参数的类或者子类
*/
@AfterReturning(value = "@annotation(MyAction)",returning = "result")
public void returning(JoinPoint point,Object result) {
System.out.println(point.getSignature().getName() + "方法的返回值是:" + result);
}
/**
* 这是一个异常通知,该通知在方法执行抛出异常时执行
*
* 如果目标方法没有异常,则通知不会被触发
*/
@AfterThrowing(value = "@annotation(MyAction)",throwing = "e")
public void throwing(JoinPoint point,Exception e) { System.out.println(">>>>>"+e.getMessage());
}
/**
* 环绕通知是上面四种通知的集大成者,因为这个通知中包含了上面四种通知的功能
*
* @param pjp 这个参数类似于Method对象
* @return
*/
@Around("@annotation(MyAction)")
public Object around(ProceedingJoinPoint pjp) {
//pjp.proceed() 就类似于method.invoke()
try {
//写在这个位置的,就是前置通知
Object proceed = pjp.proceed();
//写在这个位置的,就是后置通知
return proceed;
}catch (Throwable throwable) {
//写在这个位置的,就是异常通知
throwable.printStackTrace();
}
return null; }
}
(5)可以通过如下方法简化切点的定义:
/**
* 可以单独定义一个方法,专门用来定义切点,然后在其他方法中引用
*/
@Pointcut("@annotation(MyAction)")
public void pointcut() {
}
二、XML配置实现
(1)通过方法路径定义拦截规则,实际上只是切点的定义方式变了,其他的还是一样的。
/**
* 可以单独定义一个方法,专门用来定义切点,然后在其他方法中引用
* 第一个* 表示目标方法的返回值,可以是任意类型,*表示任意类型
* 第二个*表示类中的任意方法
* 两个.表示方法的参数任意(可有可无,类型任意)
*
* 例如,想精确定位到add方法,步骤如下:
* execution(int com.itbaizhan.service.MyCalcultor.add(int,int))
*/
@Pointcut("execution(* com.itbaizhan.service.*.*(..))")
public void pointcut() {
}
(2)使用表达式,可以较好的满足最小侵入式原则。