Spring(二)AOP、切入点表达式、AspecJ常用通知的类型、Spring中的事务管理
文章目录
一、AOP
1、定义
2、特点
3、AOP中的术语(连接点、切入点、通知、目标、代理)
4、配置
(1)下载AOP相关jar
(2)启动AspectJ支持
5、使用
6、切入点表达式
7、AspecJ常用通知的类型
(1)@Before 前置通知,在我们的方法实际执行前调用
(2)@After 后置通知,在我们的方法实际执行之后调用,与是否出现异常无关
(3)@AfterReturning 返回通知,在我们的方法执行之后调用,如果出现异常不再执行
(4)@After Throwing 异常通知,在切入点出现异常之后调用
(5)@Around 环绕通知,可以在我们要增强的方法执行之前、之后、出现异常时添加功能,其中ProceedingJoinPoint表示我们要增强的方法
二、Spring中的事务管理
1、什么是数据库事务?
2、为什么需要数据库事务?
3、Spring中的事务管理的形式
(1)形式一:编程式事务管理
(2)形式二:声明式事务管理
方式一:基于xml配置
方式二:基于注解实现
(3)基于注解实现的声明式事务管理的配置和实现
4、Spring中声明式事务管理失效的场景:
一、AOP
1、定义
AOP是Aspect Oriented Programming的缩写,意为面向切面编程,是一种将非业务代码和业务代码进行分离的一种思想。在实际开发中,有许多重复性的操作,例如事务提交、权限认证、保存日志等,需要在业务代码中重复被调用。面向切面编程,就是对非业务代码进行抽取,然后在不修改原有代码的前提下,为业务代码添加额外的功能。AOP底层使用的是动态代理技术,让一个代理对象,帮助我们调用非业务代码。
2、特点
AOP不是Spring的,而是java中的动态代理模式,是Spring使用了这一思想。
3、AOP中的术语(连接点、切入点、通知、目标、代理)
(1)连接点:类中可以被增强(添加额外功能)的方法。
(2)切入点:类中实际被增强的方法。
(3)通知:指一个切面在特定的连接点要做的事情(要增强的功能)。分为方法执行前通知、方法执行后通知、环绕通知等。
(4)目标:代理的目标对象,具体指连接点或切入点所在的类
(5)代理(Proxy):向目标对象应用通知时所创建的代理对象(目前使用的代理对象由Spring框架直接生成,我们不需要关心)
4、配置
(1)下载AOP相关jar
<!--AOP相关jar-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
(2)启动AspectJ支持
<aop:aspectj-autoproxy />
5、使用
@Component //spring管理生成CommonUtil类的对象
@Aspect //添加此标签的类中的方法可以被代理调用
public class CommonUtil {
/*@Before("execution(* com.ffyc.springpro.dao.AdminDao.*(..))") AdminDao中的所有方法*/
/*@Before("execution(* com.ffyc.springpro.dao.AdminDao.saveAdmin(..))") AdminDao中的所有saveAdmin方法*/
/*@Before("execution(* com.ffyc.springpro.dao.AdminDao.saveAdmin())") AdminDao中的无参的saveAdmin方法*/
/*@Before("execution(* com.ffyc.springpro.dao.AdminDao.saveAdmin(String))") AdminDao中的指定参数的saveAdmin方法*/
@Before("execution(* com.ffyc.springpro.dao.AdminDao.saveAdmin(..))")
public void saveLog(){
System.out.println("方法执行成功");
}
public void commit(){
System.out.println("提交事务");
}
}
6、切入点表达式
7、AspecJ常用通知的类型
(1)@Before 前置通知,在我们的方法实际执行前调用
@Before("execution(* com.ffyc.springpro.dao.*.*(..))")
public void saveLog(){
System.out.println("方法执行成功");
}
(2)@After 后置通知,在我们的方法实际执行之后调用,与是否出现异常无关
@After("execution(* com.ffyc.springpro.dao.*.*(..))")
public void commit(){
System.out.println("提交事务");
}
(3)@AfterReturning 返回通知,在我们的方法执行之后调用,如果出现异常不再执行
@AfterReturning("execution(* com.ffyc.springpro.dao.*.*(..))")
public void commit(){
System.out.println("提交事务");
}
(4)@After Throwing 异常通知,在切入点出现异常之后调用
@AfterThrowing(value = "execution(* com.ffyc.springpro.dao.*.*(..))",throwing = "e")
public void exception(Throwable e){
System.out.println("系统出现异常"+e.getMessage());
}
(5)@Around 环绕通知,可以在我们要增强的方法执行之前、之后、出现异常时添加功能,其中ProceedingJoinPoint表示我们要增强的方法
@Around("execution(* com.ffyc.springpro.dao.*.*(..))")
public void aroundAdvice(ProceedingJoinPoint joinPoint){
try {
System.out.println("打印日志");// 前置通知
Object[] args = joinPoint.getArgs();// 获取自己的方法中的参数
System.out.println(Arrays.toString(args));
joinPoint.proceed();// 调用自己的方法
System.out.println("提交事务");// 返回通知
}catch (Throwable throwable) {
System.out.println("系统出现异常:"+throwable.getMessage());// 异常通知
}
System.out.println("后置通知/最终通知");// 后置通知
}
二、Spring中的事务管理
1、什么是数据库事务?
数据库事务是对数据库一次执行的若干操作所进行的管理,数据库一次执行的若干操作就是若干条sql语句,是一个整体单元。
例如:转账
语句1:从A账户减钱
语句2:向B账户加钱
那么这两个语句必须是一个整体,要么都执行,要么都不执行。
2、为什么需要数据库事务?
为了保证数据的完整性,不能一半保存到数据库,一半没保存到数据库。
之前在jdbc中是每次执行完sql之后事务是自动进行提交的。(自动提交是有风险的)
在mybatis中是手动使用sqlSession.commit()提交事务的。(操作麻烦)
3、Spring中的事务管理的形式
(1)形式一:编程式事务管理
需要我们在代码中需要提交事务或回滚事务的位置写代码实现
(2)形式二:声明式事务管理
建立在 AOP 基础上,本质上是对方法前后进行拦截,所以声明式事务管理是方法级别的。声明式事务管理实现方式有两种
-
方式一:基于xml配置
-
方式二:基于注解实现
Spring 的 dao 框架,提供事物管理实现类是 DataSourceTransactionManager
(3)基于注解实现的声明式事务管理的配置和实现
- 配置spring事务管理器
<!-- 配置 spring 事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
- 开启注解事务管理
<tx:annotation-driven transaction-manager="transactionManager"/>
- 在类或方法上使用@Transactional 标签
如果在方法上面添加@Transactional 标签,那么该方法将会在Spring事务管理对象的管理下执行
@Transactional
public void save(){
loginDao.insertAdmin1();
System.out.println(10/0);
loginDao.insertAdmin2();
}
如果在类上面添加@Transactional 标签,那么该类中的所有方法都将会在Spring事务管理对象的管理下执行
@Service (value = "loginService")
@Transactional
public class LoginService {
@Autowired
LoginDao loginDao;
public Admin login(Admin admin){
Admin admin1 = loginDao.login(admin);
return admin1;
}
public void save(){
loginDao.insertAdmin1();
System.out.println(10/0);
loginDao.insertAdmin2();
}
}
4、Spring中声明式事务管理失效的场景:
(1)@Transactional添加在了非public的方法的上面
(2)方法在执行时异常被catch捕获了,声明式事务管理认为方法没有出现异常
(3)方法中在执行时出现编译期异常
解决方案:在@Transactional(rollbackFor = RuntimeException.class)中设置允许回滚的异常类型为Exception,即@Transactional(rollbackFor = Exception.class)
(4)数据库引擎不支持事务,比如mysql数据库中的MyISAM引擎。
解决方案:将mysql数据库中的引擎改为InnoDB