AOP(Aspect Oriented Programming):
面向切面编程,一种编程范式,指导开发者如何组织程序结构
作用:在不惊动原始设计的基础上为其进行功能增强
连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
在SpringAOP中,理解为方法的执行
切入点(Pointcut):匹配连接点的式子
在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
通知(Advice):在切入点处执行的操作,也就是共性功能
在SpringAOP中,功能最终以方法的形式呈现
通知类:定义通知的类
切面(Aspect):描述通知与切入点的对应关系
目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
代理(Proxy):目标对象无法直接完成工作,需要通过原始对象的代理对象实现
使用方法:
@EnableAspectJAutoProxy 用注解开发AOP
@Aspect 标记通知类
@Pointcut(execution()) 定义切点
@Before(切点) 将切点和通知绑定
①:导入aop相关坐标
②:定义dao接口与实现类
public interface BookDao {
public void save();
public void update();
}
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("book dao save ...");
}
public void update(){
System.out.println("book dao update ...");
}
}
③:定义通知类,制作通知
public class MyAdvice {
public void before(){
System.out.println(System.currentTimeMillis());
}
}
④:定义切入点
public class MyAdvice {
@Pointcut("execution(void dao.BookDao.update())")
private void pt(){}
}
⑤:绑定切入点与通知关系,并指定通知添加到原始连接点的具体执行位置
public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void before(){
System.out.println(System.currentTimeMillis());
}
}
AOP工作流程:
1.Spring容器启动
2.读取所有切面配置中的切入点
3.初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
匹配失败,创建对象
匹配成功,创建原始对象(目标对象)的代理对象
4.获取bean执行方法
获取bean,调用方法并执行,完成操作
获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
AOP切入点表达式:
格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
通配符:
* :单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
.. :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
+:专用于匹配子类类型
AOP通知类型:
@Before:通知方法在原始切入点方法前运行
@After:通知方法在原始切入点方法后运行
@Around:通知方法在原始切入点方法前后运行
注意事项:
a.环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
b.通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
c.对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
d.原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
e.由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before advice ...");
Object ret = pjp.proceed();
System.out.println("around after advice ...");
return ret;
}
@AfterReturning:通知方法在原始切入点方法正常执行完毕后运行
@AfterThrowing:通知方法在原始切入点方法运行抛出异常后执行
AOP通知获取数据:
获取切入点方法的参数
JoinPoint:适用于前置、后置、返回后、抛出异常后通知
@Before("pt()")
public void before(JoinPoint jp) {
Object[] args = jp.getArgs();
System.out.println(Arrays.toString(args));
}
ProceedJointPoint(是JoinPoint的子类):适用于环绕通知
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args));
Object ret = pjp.proceed();
return ret;
}
获取切入点方法返回值
返回后通知
@AfterReturning(value = "pt()",returning = "ret")
public void afterReturning(String ret) {
System.out.println("afterReturning advice ..."+ret);
}
环绕通知
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
return ret;
}
获取切入点方法运行异常信息(了解)
抛出异常后通知
@AfterThrowing(value = "pt()",throwing = "t")
public void afterThrowing(Throwable t) {
System.out.println("afterThrowing advice ..."+ t);
}
环绕通知
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) {
Object ret = null;
try {
ret = pjp.proceed();
} catch (Throwable t) {
t.printStackTrace();
}
return ret;
}