关于Aop的一些内容

Aop简介

Aop:面向切面编程

作用:在不惊动原始设计的情况下为其进行功能增强

Aop的核心概念:程序执行过程中的任意位置,粒度为执行方法,抛出异常,设置变量等

在SpringAop,理解为方法的执行

切入点(Pointcut):匹配连接点的式子
在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法.通知(Advice):在切入点处执行的操作,也就是共性功能
在SpringAOP中,功能最终以方法的形式呈现
通知类:定义通知的类
切面(Aspect):描述通知与切入点的对应关系

Aop入门案例:

1.导入Aop相关坐标

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>

2.定义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.printin("book dao update ...");

}

3.定义通知类,制作通知类

public class MyAdvice {
public void before(){
System.out.println(System.currentTimeMiLlis());

      }

}

4.定义切入点

public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt();

}

5.绑定切入点与通知关系,并指定通知添加到原始链接点的具体执行位置

public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void before(){
System.out.println(System.currentTimeMiLlis());

       }

}

6.定义通知类受Spring容器管理,并定义当前类为切面类

@Component
@Aspect
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切入点表达形式:

切入点表达式标准格式:动作关键字(访问修饰符返回值 包名.类/接口名.方法名(参数)异常名)
execution
(public User com.itheima.service.UserService.findById (int))

动作关键字:描述切入点的行为动作,例如execution表示执行到指定切入点

访问修饰符:public,private等,可以省略
返回值

包名

类/接口名

方法名

参数
异常名:方法定义中抛出指定异常,可以省略

可以使用通配符描述切入点,快速描述
1. *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
execution (public * com.itheima.*.UserService.find*(*))
匹面com.itheima包下的任意包中的UserService类或接口中所有fnd开头的带有一个参数的方法
2. .. :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
execution (public User com..UserService.findById (..))

匹配com包下的任意包中的UserService类或接口中所有名称为findByld的方法

3. +:专用于匹配子类类型
execution(* *..*Service+.*(..))

书写技巧
所有代码按照标准规范开发,否则以下技巧全部失效
描述切入点通常描述接口,而不描述实现类
访问控制修饰符针对接口开发均采用public描述(可省略访问控制修饰符描述)

返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用*通配快速描述

包名书写尽量不使用.匹配,效率过低,常用*做单个包描述匹配,或精准匹配
接口名/类名书写名称与模块相关的采用*匹配,例如UserService书写成*Service,绑定业务层接口名

方法名书写以动词进行精准匹配,名词采用*匹配,例如getByld书写成getBy*,selectAI/书写成selectAl

参数规则较为复杂,根据业务方法灵活调整
通常不使用异常作为匹配规则

Aop的通知类型

Aop通知共分为5种类型

前置通知

•名称:@Before
·类型:方法注解
·位置:通知忘法定义上方
•作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行
·范例
@Before("pt()")
public void before() {
System.out.println("before advice ...");

}

相关属性:value(默认):切入方法名,格式名为类名。方法名()

后置通知

•名称:@After
•类型:方法注解
·位置:通知方法定义上方
·作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法后运行
·范例:
@After("pt()")
public void after()(
System.out.println("after advice ...");

}

相关属性:value(默认)切入点方法名,格式为类名.方法名

环绕通知

•名称:@Around(重点,常用)
·类型:方法注解
·位置:通知方法定义上方
•作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前后运行
·范例:
@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;

}

@Around注意事项
1.环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
2.通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
3.对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
4.原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
5.由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

返回后通知

•名称:@AfterReturning(了解)
·类型:方法注解
·位置:通知方法定义上方
·作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法正常执行完毕后运行
•范例
@AfterReturning("pt()")
public void afterReturning() {
System.out.println("afterReturning advice ...");

}
·相关属性:value(默认):切入点方法名,格式为类名方法名0

抛出异常后通知

•名称:@AfterThrowing(了解)
·类型:方法注解
·位置:通知方法定义上方
•作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法运行抛出异常后执行
·范例
@AfterThrowing("pt()")
public void afterThrowing(){
System.out.println("afterThrowing advice ...");

}
·相关属性:value(默认):切入点方法名,格式为类名.方法名

Aop通知获取数据

获取切入点方法的参数
JoinPoint:适用于前置、后置、返回后、抛出异常后通知

@Before("pt()")
public void before(JoinPoint jp) {
Object[] args = jp.getArgs();
System.out.println(Arrays.tostring(args));

}
ProceedJointPoint:适用于环绕通知

@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,

}
获取切入点方法运行异常信息
抛出异常后通知
环绕通知

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值