Spring(二)AOP、切入点表达式、AspecJ常用通知的类型、Spring中的事务管理

文章目录

一、AOP

1、定义

2、特点

3、AOP中的术语(连接点、切入点、通知、目标、代理)

4、配置

(1)下载AOP相关jar

(2)启动AspectJ支持

5、使用

6、切入点表达式

7、AspecJ常用通知的类型

[(1)@Before 前置通知,在我们的方法实际执行前调用](#(1)@Before 前置通知,在我们的方法实际执行前调用)

[(2)@After 后置通知,在我们的方法实际执行之后调用,与是否出现异常无关](#(2)@After 后置通知,在我们的方法实际执行之后调用,与是否出现异常无关)

[(3)@AfterReturning 返回通知,在我们的方法执行之后调用,如果出现异常不再执行](#(3)@AfterReturning 返回通知,在我们的方法执行之后调用,如果出现异常不再执行)

[(4)@After Throwing 异常通知,在切入点出现异常之后调用](#(4)@After Throwing 异常通知,在切入点出现异常之后调用)

[(5)@Around 环绕通知,可以在我们要增强的方法执行之前、之后、出现异常时添加功能,其中ProceedingJoinPoint表示我们要增强的方法](#(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

XML 复制代码
<!--AOP相关jar-->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>5.2.2.RELEASE</version>
</dependency>

(2)启动AspectJ支持

XML 复制代码
<aop:aspectj-autoproxy />

5、使用

java 复制代码
@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 前置通知,在我们的方法实际执行前调用

java 复制代码
@Before("execution(* com.ffyc.springpro.dao.*.*(..))")
    public void saveLog(){
        System.out.println("方法执行成功");
    }

(2)@After 后置通知,在我们的方法实际执行之后调用,与是否出现异常无关

java 复制代码
@After("execution(* com.ffyc.springpro.dao.*.*(..))")
    public void commit(){
        System.out.println("提交事务");
    }

(3)@AfterReturning 返回通知,在我们的方法执行之后调用,如果出现异常不再执行

java 复制代码
@AfterReturning("execution(* com.ffyc.springpro.dao.*.*(..))")
    public void commit(){
        System.out.println("提交事务");
    }

(4)@After Throwing 异常通知,在切入点出现异常之后调用

java 复制代码
@AfterThrowing(value = "execution(* com.ffyc.springpro.dao.*.*(..))",throwing = "e")
    public void exception(Throwable e){
        System.out.println("系统出现异常"+e.getMessage());
    }

(5)@Around 环绕通知,可以在我们要增强的方法执行之前、之后、出现异常时添加功能,其中ProceedingJoinPoint表示我们要增强的方法

java 复制代码
@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事务管理器
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 标签

如果在方法上面添加@Transactional 标签,那么该方法将会在Spring事务管理对象的管理下执行

java 复制代码
@Transactional
    public void save(){
        loginDao.insertAdmin1();
        System.out.println(10/0);
        loginDao.insertAdmin2();
    }

如果在类上面添加@Transactional 标签,那么该类中的所有方法都将会在Spring事务管理对象的管理下执行

java 复制代码
@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

相关推荐
天天向上杰几秒前
简识JVM的栈帧优化共享技术
java·jvm
方圆想当图灵19 分钟前
缓存之美:万文详解 Caffeine 实现原理(下)
java·redis·缓存
栗豆包33 分钟前
w175基于springboot的图书管理系统的设计与实现
java·spring boot·后端·spring·tomcat
等一场春雨1 小时前
Java设计模式 十四 行为型模式 (Behavioral Patterns)
java·开发语言·设计模式
萧若岚2 小时前
Elixir语言的Web开发
开发语言·后端·golang
Channing Lewis2 小时前
flask实现重启后需要重新输入用户名而避免浏览器使用之前已经记录的用户名
后端·python·flask
Channing Lewis2 小时前
如何在 Flask 中实现用户认证?
后端·python·flask
酱学编程2 小时前
java中的单元测试的使用以及原理
java·单元测试·log4j
我的运维人生2 小时前
Java并发编程深度解析:从理论到实践
java·开发语言·python·运维开发·技术共享
一只爱吃“兔子”的“胡萝卜”3 小时前
2.Spring-AOP
java·后端·spring