目录
一、Aop( Aspect Oriented Programming)
二、springAOP实现
1.XML实现
2.注解实现
三、spring事务管理
一、Aop( Aspect Oriented Programming)
将程序中的非业务代码抽取,使非业务代码与业务代码相隔离,为目标类创建一个代理对象让代理对象调用目标类中的方法也就是非业务代码,提高了代码的复用率和灵活性,提高开发效率,降低了非业务代码与业务代码的耦合性。
专业名词:
- 连接点(Joinpoint):类中可以被增强的方法(新增修改等);
- 切入点(pointcut):实际被增强的方法;
- 通知(Advice): 一个切面在特定的连接点要做的事情(方法被增强的功能),分为前置通知、后置通知、异常;
- 切面(Aspect):把通知添加到切入点的整个过程称为切面;
- 目标(Target): 代理的目标对象(连接点,切入点所在类);
- 代理(Proxy): 向目标对象应用通知时创建的代理对象。
应用场景:
保存日志、事务管理、权限控制、统一异常管理、缓存、对象池管理等
二、springAOP实现
示例一个日志通知功能
首先添加spring—aspect jar包:
<!--aspectj-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
有两种实现方式:XML和注解
1.XML实现
将通知方法所在的类以XML的方法交给spring管理:
<bean id="commonUtil" class="com.yyds.spring.util.CommonUtil"></bean>
配置通知和切入点之间的关系:
<aop:config>
<!--切入点 实际被蹭强的方法-->
<aop:pointcut id="allmethods" expression="execution(* com.yyds.spring.dao.*.*(..))"/>
<!--切面 把通知添加到切入点的整个过程称为切面. -->
<aop:aspect ref="commonUtil">
<!--前置通知-->
<!--<aop:before method="savelog" pointcut-ref="allmethods"></aop:before>-->
<!--最终通知 ,无论是否有异常,都会通知-->
<!--<aop:after method="savelog" pointcut-ref="insert"></aop:after>-->
<!--后置通知,如果有异常,不会通知-->
<!--<aop:after-returning method="savelog" pointcut-ref="allmethods"></aop:after-returning>-->
<!--有异常才会通知-->
<!--<aop:after-throwing method="savelog" pointcut-ref="allmethods"></aop:after-throwing>-->
<!--环绕通知-->
<aop:around method="savelog" pointcut-ref="allmethods"></aop:around>
</aop:aspect>
</aop:config>
表示dao包下的所有类中的方法都可以被增强
- before:前置通知
- after-returning:后置通知,有异常不执行,在方法正常执行完成之后
- after:最终通知,无论是否有异常,最终都会执行
- after-throwing:有异常才会通知
环绕通知:around,包含上面所有的分布通知
环绕示例:
public class CommonUtil_back {
void savelog(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("前置通知");
try {
System.out.println(new Date()+"日志");
Object[] objects= proceedingJoinPoint.getArgs();
System.out.println(Arrays.toString(objects));
// 调用我们目标的切入点
proceedingJoinPoint.proceed();
System.out.println("后置通知");
}catch (Throwable e){
System.out.println(e.getMessage()+"异常通知");
}
System.out.println("最终通知");
}
}
JoinPoint和ProceedingJoinPoint:
ProceedingJoinPoint是JoinPoint的子类;
ProceedingJoinPoint 比 JoinPoint仅仅多 proceed()方法;
尽量在around通知时,使用ProceedingJoinPoint作为参数;
在用其他通知时,使用JoinPoint作为参数。
2.注解实现
1. 开启springAOP注解方式:<aop:aspectj-autoproxy />
2. 在通知的类上添加注解:@Component和@Aspect
前置、后置、最终、异常通知 :
@Before("execution(* com.yyds.spring.dao.*.*(..))")
@After("execution(* com.yyds.spring.dao.*.*(..))")
@AfterReturning("execution(* com.yyds.spring.dao.*.*(..))")
@AfterThrowing(value = "execution(* com.yyds.spring.dao.*.*(..))",throwing = "e")
void savelog(JoinPoint joinPoint){
System.out.println(new Date()+"日志");
}
环绕通知:
@Around("execution(* com.yyds.spring.dao.*.*(..))")
void savelog(ProceedingJoinPoint point){
System.out.println("前置通知");
try {
System.out.println(new Date()+"日志");
Object[] args = point.getArgs();
System.out.println(Arrays.toString(args));
point.proceed();
System.out.println("后置通知");
}catch (Throwable e){
System.out.println("异常通知"+e.getMessage());
}
System.out.println("最终通知");
}
环绕通知格式要使用try{ }catch( )形式
三、spring事务管理
程序在顺序执行过程中,任何一步都可能出现异常,导致后面程序不执行,很有可能使业务逻辑未完成,执行结果并不可靠。例如在转账时,A向B转500r时,若A的余额扣掉500r时,程序中出现异常,导致B的余额并未增加500r,这样就使得程序并为完成转账功能。事务管理的作用就是使这些操作看成一个整体,要么都执行,要么都不执行。保持事务的原子性。
spring可以自动提交和回滚事务
1.编程式:在项目中很少使用,这种方式需要注入一个事务管理对象TransactionTemplate ,然后在我们代码中需要提交事务或回滚事务时自己写代码实现。
2.声明式
XML配置实现和注解实现
注解实现:
配置事物管理器:
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
开启注解事务管理
<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>