AOP的核心概念
-
概念:AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,是对一个类的方法在不进行任何修改的前提下实现功能增强。
-
作用:在不惊动原始设计的基础上为方法进行功能增强,底层采用的是代理模式实现的
-
核心概念
- 代理(Proxy):SpringAOP的核心本质是采用代理模式实现的
- 连接点(JoinPoint):在SpringAOP中,理解为任意方法的执行
- 切入点(Pointcut):要进行增强的方法
- 切入点表达式:要进行增强的方法的描述方式
- 通知(Advice):若干个方法的共性功能,在切入点处执行,最终体现为一个方法
- 切面(Aspect):描述通知与切入点的对应关系
- 目标对象(Target):被代理的原始对象成为目标对象
-
切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
- 描述切入点通常描述接口,而不描述实现类,如果描述到实现类,就出现紧耦合了
- 访问控制修饰符针对接口开发均采用public描述(可省略访问控制修饰符描述)
- 通常不使用异常作为匹配规则
常用的两种:
execution(* com.itheima.*.*Service.find*(..))
将项目中所有业务层方法的以find开头的方法匹配
execution(* com.itheima.*.*Service.save*(..))
将项目中所有业务层方法的以save开头的方法匹配
通知类:定义切入点,定义通知,描述切面。
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
使用AOP要在springConfig配置文件中开启注解格式AOP功能
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}
五种通知类型
-
前置通知
-
后置通知
-
环绕通知(重点)
- 环绕通知依赖形参ProceedingJoinPoint才能实现对原始方法的调用
- 环绕通知可以隔离原始方法的调用执行
- 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,最好设定为Object类型,当连接点返回值为void时则返回null
- 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须要处理Throwable异常
-
返回后通知
-
抛出异常后通知
通知中获取参数
-
获取切入点方法的参数,所有的通知类型都可以获取参数(重点)
- JoinPoint:适用于前置、后置、返回后、抛出异常后通知
- ProceedingJoinPoint:适用于环绕通知
-
获取切入点方法返回值,前置和抛出异常后通知是没有返回值,后置通知可有可无,所以不做研究
- 返回后通知
- 环绕通知
-
获取切入点方法运行异常信息,前置和返回后通知是不会有,后置通知可有可无,所以不做研究
- 抛出异常后通知
- 环绕通知
pjp在通知中获取原始方法的信息
- pjp获取连接点接口名和方法名
//获取执行签名信息
Signature signature = pjp.getSignature();
//通过签名获取执行操作名称(接口名)
String className = signature.getDeclaringTypeName();
//通过签名获取执行操作名称(方法名)
String methodName = signature.getName();
- pjp获取获取切入点方法的参数
Object[] args = pjp.getArgs();
注意:pjp.proceed()方法是有有参和无参两个构造方法。调用无参数的proceed,当原始方法有参数,会在调用的过程中自动传入参数。但是当需要修改原始方法的参数时,就只能采用带参数的方法。
有了这个特性后,我们就可以在环绕通知中对原始方法的参数进行拦截过滤,避免由于参数的问题导致程序无法正确运行,保证代码的健壮性。
AOP工作流程
上面介绍AOP的工作流程中,我们提到了两个核心概念,分别是:
- 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
- 代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现
上面这两个概念比较抽象,简单来说,
目标对象就是要增强的类对应的对象,也叫原始对象,不能说它不能运行,只能说它在运行的过程中对于要增强的内容是缺失的。
SpringAOP是在不改变原有设计(代码)的前提下对其进行增强的,它的底层采用的是代理模式实现的,所以要对原始对象进行增强,就需要对原始对象创建代理对象,在代理对象中的方法把通知内容加进去,就实现了增强,这就是我们所说的代理(Proxy)。
Spring事务管理
- 事务作用:在数据层保障一系列的数据库操作同成功同失败
- Spring事务作用:在数据层 或 业务层保障一系列的数据库操作同成功同失败
Spring为事务管理提供了一个平台事务管理器PlatformTransactionManager
,同时提供了一个具体的实现类DataSourceTransactionManager
事务管理器,其内部采用的是JDBC的事务。注意: 事务管理器要根据使用技术进行选择,Mybatis框架使用的是JDBC事务,所以可以直接使用spring的DataSourceTransactionManager
,在JdbcConfig配置类中配置事务管理器。
在SpringConfig的配置类中开启事务注解
Spring事务角色
- 事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法
- 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法
注意:
目前的事务管理是基于
DataSourceTransactionManager
和SqlSessionFactoryBean
使用的是同一个数据源。
Spring的事务只会对Error异常
和RuntimeException异常
及其子类进行事务回顾,其他的异常类型是不会回滚的。
事务传播行为
事务传播行为:事务协调员对事务管理员所携带事务的处理态度。需要用propagation属性
。例如