AOP
AOP(Aspect Oriented Programming)面向切面编程,aop是一种设计思想,是oop面向对象编程的一种补充和完善,它通过预编译方式和运行期间动态代理的方式达成在不修改源代码的情况下,实现对业务逻辑的增强。
相关术语
横切关注点:从目标类每个方法中抽取出来的非核心业务代码
通知:将横切关注点封装到一个类中,这个类就叫做切面,封装的横切关注点就是一个通知,也叫通知方法。
非核心业务代码在目标类中就叫做横切关注点,在切面类中就是通知
连接点:目标类中抽取非核心业务代码的方法
切入点:要实现业务增强的方法
基于注解的AOP
在IOC的基础上导入aop的依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
</dependencies>
spring配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--开启注解扫描,使注解生效将切面和目标类都交给springioc来管理-->
<context:component-scan base-package="com.mao"/>
<!--开启基于注解的aop功能-->
<aop:aspectj-autoproxy/>
</beans>
切面类要加@Aspect将该类声明为切面
/**
* 切面类
*/
@Component
@Aspect//将当前组件标识为切面
public class LoggerAspect {
@Pointcut("execution(* com.mao.CalculatorImpl.*(..))")
public void pointCut()
{
}
//前置通知
@Before("pointCut()")
public void before(JoinPoint joinPoint)
{
//获取连接点对应方法的方法名
Signature signature = joinPoint.getSignature();
//获取连接点对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("前置通知。。。。。");
}
//后置通知
@After("pointCut()")
public void after(JoinPoint joinPoint)
{
//获取连接点对应方法的方法名
Signature signature = joinPoint.getSignature();
//获取连接点对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("后置通知");
}
//返回通知,在目标方法返回值之后执行
//在返回通知中如果想要获取目标方法的返回值,可以通过returning属性
//返回通知和后置通知的区别:
//后置通知无论是否出现异常都会执行,而返回通知是出现异常就不再执行
@AfterReturning(value = "pointCut()",returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result)
{
System.out.println("返回通知");
}
//异常通知
//获取目标对象的方法的异常,通过throwing属性
@AfterThrowing(value = "pointCut()",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Throwable ex)
{
System.out.println("异常通知");
}
//环绕通知
//环绕通知方法的返回值和目标方法的返回值保持一致
//ProceedingJoinPoint 对象用来表示目标方法的执行
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint){
Object result=null;
try {
System.out.println("环绕通知---前置");
//表示目标方法的执行
result=joinPoint.proceed();
System.out.println("环绕通知---返回");
}
catch (Throwable e)
{
e.printStackTrace();
System.out.println("环绕通知---异常");
}
finally {
System.out.println("环绕通知---后置");
}
return result;
}
}
切面的优先级
可以通过@order注解的value属性设置优先级,默认值为Integer的最大值。
@order注解的value值越小,优先级越高
基于注解的声明式事务
声明式事务的配置步骤:
1.在spring核心配置文件中配置事务管理器
2.开启事务注解驱动
3.在要进行事务管理的类或方法上添加@Transactional注解
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransaction">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启事务的注解驱动
将使用@Transactional注解所标识的方法或类中的所有方法使用事务进行管理
-->
<tx:annotation-driven transaction-manager="transactionManager"/>
事务的属性
1.只读
对于查询操作,可以将事务设置为只读,这样数据库就可以针对查询操作来进行优化。
@Transactional(
readOnly=true
)
2.超时
事务在执行的过程中,由于某些问题导致程序卡住,从而长时间的占用数据库的资源,此时应该对该事务执行回滚操作。
可以对事务设置超时,减少不必要的资源的浪费
@Transactional(
timeout=3//设置超时时间为3秒,默认为-1,表示一直等待
)
3.设置回滚策略
4.事务的四种隔离级别
事务的隔离性是指在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。
可能导致的问题有
1.脏读: 一个事务读到另一个事务未提交的更新数据。
2.不可重复读: 一个事务两次读同一行数据,可是这两次读到的数据不一样。
3.幻读: 一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
@Transactional(
isolation=Isolation.DEFAULT//使用默认的隔离级别
)
5.事务的传播行为
事务A,B都开启了@Transactional注解,事务A去调用事务B
@Transactional(
propagation=Propagation.REQUIRED//使用的是调用者的事务,如A
propagation=Propagation.REQUIRED.NEWS//使用的是被调用者的事务,如B
)