Spring AOP
一个配置实例:
添加依赖:
<!-- aspectj依赖, 用于解析切入点表达式-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
主配置文件:
<!-- 被代理类-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!-- 切面类注册到 IOC -->
<bean id="logger" class="com.itheima.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面类 -->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<!-- 配置切入点表达式为全称-->
<aop:before method="printLog" pointcut="execution(public void com.itheima.service.AccountServiceImpl())"></aop:before>
</aop:aspect>
</aop:config>
切面类(提供增强方法的类) :
public class Logger {
public void printLog(){
System.out.println("Logger类中的pringLog方法开始记录日志了。。。");
}
}
切入点表达式的写法:
全通配写法: * *..*.*(..)
实际开发中, 使用 切到service层所有实现类的所有方法, 比如: * com.zzy.service.impl.*.*(..)
环绕通知, 以及单独为切入点表达式配置的标签
注意: <aop:pointcut 标签要么在 <aop:aspect 内部, 表示此 切入点表达式只适用于这个切面, 或者此标签在<aop:aspect 之前的同级标签, 表示此 切入点表达式通用
<!--配置AOP-->
<aop:config>
<!-- 配置切入点表达式 id属性用于指定表达式的唯一标识。expression属性用于指定表达式内容
此标签写在aop:aspect标签内部只能当前切面使用。
它还可以写在aop:aspect外面,此时就变成了所有切面可用
-->
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.* (..))"></aop:pointcut>
<!--配置切面 -->
<aop:aspect id="logAdvice" ref="logger"></aop:aspect>
<!-- 配置环绕通知 详细的注释请看Logger类中-->
<aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
切面类:
public class Logger{
// 环绕通知
public Object aroundPringLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
Object[] args = pjp.getArgs();//得到方法执行所需的参数
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");
rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");
return rtValue;
}catch (Throwable t){
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
throw new RuntimeException(t);
}finally {
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
}
}
}
使用注解替代aop的 xml配置
主配置文件:
<!-- 配置spring开启注解AOP的支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
或者采用全注解方式, @EnableAspectJAutoProxy 替代上面的 aop自动代理配置
@Configuration //主配置
@Import(JdbcConfig.class) //引入的配置
@ComponentScan(basePackages = {"com.zzy"})
@EnableAspectJAutoProxy //aop代理自动开启
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
}
切面类:
@Component("logger")
@Aspect//表示当前类是一个切面类
public class Logger{
// 配置切入点表达式, 仅适用本切面
@Pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt1(){}
// 环绕通知, 指定切入点表达式
@Around("pt1()")
public Object aroundPringLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
Object[] args = pjp.getArgs();//得到方法执行所需的参数
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");
rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");
return rtValue;
}catch (Throwable t){
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
throw new RuntimeException(t);
}finally {
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
}
}
}
Spring 事务
demo地址 事务的动态代理
AOP结合自定义事务管理器(手写)
package com.itheima.utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接
*/
@Component("txManager")
@Aspect
public class TransactionManager {
@Autowired
private ConnectionUtils connectionUtils;
@Pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt1(){}
/**
* 开启事务
*/
public void beginTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 提交事务
*/
public void commit(){
try {
connectionUtils.getThreadConnection().commit();
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 回滚事务
*/
public void rollback(){
try {
connectionUtils.getThreadConnection().rollback();
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 释放连接
*/
public void release(){
try {
connectionUtils.getThreadConnection().close();//还回连接池中
connectionUtils.removeConnection();
}catch (Exception e){
e.printStackTrace();
}
}
@Around("pt1()")
public Object aroundAdvice(ProceedingJoinPoint pjp){
Object rtValue = null;
try {
//1.获取参数
Object[] args = pjp.getArgs();
//2.开启事务
this.beginTransaction();
//3.执行方法
rtValue = pjp.proceed(args);
//4.提交事务
this.commit();
//返回结果
return rtValue;
}catch (Throwable e){
//5.回滚事务
this.rollback();
throw new RuntimeException(e);
}finally {
//6.释放资源
this.release();
}
}
}
基于xml 的声明式事务
标签关系: <aop:config 包含 <aop advisor 依赖 <tx:advice 依赖 txManager bean 依赖注入 DataSource bean
<!-- 配置aop-->
<aop:config>
<!-- 配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
<!--建立切入点表达式和事务通知的对应关系 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
<!-- 配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置事务的属性
isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
注意: <tx:method 标签内定义了 txManager所管理的方法的命名规范
使用注解配置事务管理器
使用 <tx:annotation-driven transaction-manager=“transactionManager”/> 开启 spring对注解事务的支持, 或者在全注解配置下, 添加 @EnableTransactionManagement
用@Transactional 注解标记方法或类, 即可代替上面的 <aop:config 和 <tx:advice
注意: spring 声明式事务的两种配置方法, 采用xml 则只需遵循方法命名规范, 采用注解, 需要逐个类地配置@Transactional