AOP详解:
1.介绍:
面向切面编程,是一种将非业务代码与业务代码进行分离的一种思想,在实际开发中,往往有许多重复操作,例如事务提交,权限验证,保存口志等功能需要在业务代码重复调用,面向切面编程,就是将非业务代码进行抽取,然后在不修改原来代码的前提下,为我们的业务代码,添加额外的功能.
面向切面编程的好处就是: 减少重复,专注业务;
注意:面向切面编程只是面向对象编程的一种补充
2.核心原理:
使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑.
3.使用案例:
事务处理:开启事务,关闭事务,出现异常后回滚事务 权限判断:在执行方法前,判断是否具有权限 日志:在执行前进行日志处理
4.总结:
AOP就是把重复的非业务代码通过动态代理的方式实现,让开发者配置一次后就不用再考虑重复的非业务代码
AOP思想不是spring中特有的,是java中的动态代理模式,是spring框架使用了这一思想
5.基本概念:
(1) 连接点(Joinpoint):类中可以被增强(可以添加额外功能的方法)的方法
(2) 切入点(Pointcut):类中实际被增强的方法,把额外功能实际切入的方法
(3) 通知(Advice):是指一个切面在特定的连接点要做的事情(增强的功能),通知分为方法执行前通知,方法执行后通知,环绕通知等
(4) 目标(Target):代理的目标对象,连接点和切入点方法所在的类
(5) 代理(Proxy):向目标对象应用通知时创建的代理对象(目前使用的代理对象由spring框架生成,目前我们不需要关心)
6.springAOP实现:
下载 AOP 相关 jar
xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
AspectJ 中常用的通知有五种类型:
注解放在对应的方法上方:
java
@Before("execution(* com.lzy.springpro.dao.*.*(..))")
public void saveLog(){
System.out.println("方法执行成功");
}
AOP中的通知类型:
@Before 前置通知,在我们的方法实际执行前调用
@After 后置通知,子啊方法执行后执行,即使出现异常也会执行
@AfterReturning 返回通知,方法成功执行之后通知,出现异常不通知
@AfterThrowing 异常通知,当切入点出现异常执行,没有异常不执行
@Around 环绕通知,方法执行前后都有通知,可以实现其余四个通知
启动 AspectJ 支持:
<aop:aspectj-autoproxy/>
同时spring.xml还要配置AOP相关:
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
java
@Before("execution(* com.lzy.springpro.dao.AdminDao.saveAdmin(..))")
@After("execution(* com.lzy.springpro.dao.*.*(..))")
@AfterReturning("execution(* com.lzy.springpro.dao.*.*(..))")
@AfterThrowing("execution(* com.lzy.springpro.dao.*.*(..))")
@Around("execution(* com.lzy.springpro.dao.*.*(..))")
Around:
java
@Around("execution(* com.lzy.springpro.dao.*.*(..))")
public void around(ProceedingJoinPoint joinPoint){
try{
System.out.println("保存日志"); //前置通知
Object[] args=joinPoint.getArgs(); //获取方法中的参数
System.out.println(Arrays.toString(args));
joinPoint.proceed(); //调用我们自己的方法
System.out.println("提交事务"); //返回通知
}catch (Throwable e){
System.out.println("系统异常"); //异常通知
}
System.out.println("后置通知"); //后置通知
}
7.Spring 事物管理
什么是数据库事务
数据库事务是一次对数据库执行的若干操作的管理,这一次操作的若干条sql语句,应该是一个整体的单元
例如转账:
一次转账操作,对于用户来讲已是一个操作,但是这一次操作中,会执行多条sql语句,例如语句1:从A账户减钱 语句2:从B账户加钱。两个语句必须是一个整体,要么都成功执行,要么都不执行。这是事务特征的最基本的原子性特征。只有当一次操作完成后,向数据库提交事务后,数据库才会将多条sql真正的执行。
为什么需要事务?
保证数据的完整性,不能一半保存到数据库,一半没保存成功。
之前在jdbc中是每次执行完sql后,事务九自动提交的。(自动提交是有风险的)在mybatis中是手动sqlSession.commit();提交的,这很麻烦
spring事务管理:
spring事务管理就是AOP的基础上,当我们的方法完全执行后,再提交事务,如果方法中有异常,就不提交事务。
spring中的事务管理有两种方式:
1.编程式事务
需要我们再业务代码中手动提交
2.声明式事务
配置事物管理器
xml
<!-- 配置 spring 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
注解方式
xml
<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
在类或方法上使用@Transactional :
java
/*
@Transactional 可以添加在类上,这样类中所有的方法都在事务管理中进行
也可以添加在方法上,只有所添加的方法再事务管理中进行
*/
@Transactional(rollbackFor = Exception.class)
public class LoginService {
......
}
声明式事务几种失效场景:
1.@Transactional用在了非public方法上面(受封装的不能直接获取的)
2.异常被catch捕获了,认为方法没有出现异常
3.默认出现编译期异常,事务失效,可以在@Transactional(rollbackFor=Exception.class)设置回滚异常类型为Exception,这样即使出现编译期异常,也是有效的
4.数据库引擎不支持事务,目前mysql中只有innodb引擎支持事务