在程序运行期间,动态的将一段代码插入到原来方法的某些位置
比如:我们购买东西会验证当前登录的账号,添加商品到购物车也可要验证。那么我们只需要单独设计一个用于验证用户的模块,插入到购买,添加购物车等操作。实现了功能与功能之间的解耦。
前置通知,后置通知,异常通知
切面就是包含通知代码的类
首先在applicationContext.xml文件中写上:
<?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/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描com.student下面的所有的注解 -->
<context:component-scan base-package="com.student"></context:component-scan>
<!--
使用注解配置AOP切面编程(实现自动代理功能)
也就是说配置的@Aspect生效
-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
写一个需要通知的方法,添加@Component注解,代表把这个类放到spring容器中去(id的名字为(add)即类名的首字母小写)
package com.student.method;
import org.springframework.stereotype.Component;
@Component
public class Add {
public int addSomething(int a,int b) {
return a+b;
}
}
在写一个通知类
@Aspect是把这个类弄成一个通知类
@Component是将其放入到spring容器对象中去
package com.student.until;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class Advice {
//前置通知,需要告诉这个通知你是哪个哪个类的哪个方法的通知
//这个是spring切点表达式也就是你是哪个方法的前置通知
@Before(value ="execution(* com.student.method.Add.addSomething(int, int))")
public void beforeMathod() {
System.out.println("我是前置通知");
}
@After(value ="execution(* com.student.method.Add.addSomething(int, int))")
public void afterMathod() {
System.out.println("我是后置通知");
}
}
package com.student.until;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class Advice {
@Before(value ="execution(* com.student.method.Add.addSomething(int, int))")
public void beforeMathod() {
System.out.println("我是前置通知");
}
@After(value ="execution(* com.student.method.Add.addSomething(int, int))")
public void afterMathod() {
System.out.println("我是后置通知");
}
@AfterReturning(value = "execution(* com.student.method.Add.addSomething(int, int))")
public void returnMethod() {
System.out.println("我是返回通知");
}
@AfterThrowing(value = "execution(* com.student.method.Add.addSomething(int, int))")
public void exceptionMethod() {
System.out.println("我是异常通知");
}
}
利用JoinPoint获取方法名和参数
@Before(value ="execution(* com.student.method.Add.addSomething(int, int))")
public void beforeMathod(JoinPoint jp) {
System.out.println("前置通知");
System.out.println("方法名:"+jp.getSignature().getName()+"参数:"+Arrays.asList(jp.getArgs()));
}
在方法上面添加一个参数Object result,切点值加returning="result"
在方法上面添加Exception e接受抛出的异常
在配置切点的的注解中添加throwing="e"
@Around(value = "execution(* com.student.method.Add.addSomething(int, int))")
public static Object around(ProceedingJoinPoint pjp) {
Object result=null;
try {
System.out.println("前置通知。");
result=pjp.proceed();//执行方法
System.out.println("后置通知");
} catch (Throwable e) {
System.out.println("异常通知。");
e.printStackTrace();
throw e;
}finally {
System.out.println("返回通知");
}
return result;
}
注意事项:
如果写了普通通知和环绕通知
1.环绕通知优先于普通通知先执行
2.一定要把目标方法的返回值返回,要不然普通通知中收不到值
3.环绕方法出现异常,一定要把异常抛出,要不然普通方法不会出现异常,普通通知会执行返回值通知,获取的返回值为NULL
1.定义一个 静态 的空的方法
2.@Pointcut写入需要设置的切点
3.直接在value后面写入方法名就可
@Pointcut("execution(* com.student.method.Add.addSomething(int, int))")
public static void pointCutOne() {}
@Before(value ="pointCutOne()")
public void beforeMathod(JoinPoint jp) {
System.out.println("前置通知");
System.out.println("方法名:"+jp.getSignature().getName()+"参数:"+Arrays.asList(jp.getArgs()));
}
默认的顺序,是按照A到Z的首字母顺序排序(先进后出),但是在实际的开发中不可能特地的起名字,所以我们可以使用@Order(12344…),数字越小优先级越高。
因为这两天比较忙,所以占时只写了这么多笔记,明天继续补笔记,三天是不可能了,那就四天吧!!加油