Spring AOP

什么是AOP编程

AOP: Aspect Oriented Programming 面向切面编程。
  面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面(方面)编程。
  主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
  主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改 变这些行为的时候不影响业务逻辑的代码。
  可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。 AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。
假设把应用程序想成一个立体结构的话,OOP的利刃是纵向切入系统,把系统划分为很多个模块(如:用户模块,文章模块等等),而AOP的利刃是横向切入系统,提取各个模块可能都要重复操作的部分(如:权限检查,日志记录等等)。由此可见,AOP是OOP的一个有效补充。
注意:AOP不是一种技术,实际上是编程思想。凡是符合AOP思想的技术,都可以看成是AOP的实现。
Aop, aspect object programming 面向切面编程
功能: 让关注点代码与业务代码分离!

AOP底层实现原理

代理设计模式

通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。既(AOP微实现) ,AOP核心技术面向切面编程。
在这里插入图片描述

代理的分类
静态代理(静态定义代理类)

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

public interface IUserDao {
  void save();
}
public class UserDao implements IUserDao {
  publicvoid save() {
     System.out.println("已经保存数据...");
  }
}
//代理类
public class UserDaoProxy implements IUserDao {
  private IUserDao target;
  public UserDaoProxy(IUserDao iuserDao) {
     this.target = iuserDao;
  }
  public void save() {
     System.out.println("开启事物...");
     target.save();
     System.out.println("关闭事物...");
  }
}
动态代理(Jdk自带动态代理)

1)原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下)
2)实现方式:

  1. 通过实现InvocationHandler接口创建自己的调用处理器
    IvocationHandler handler = new InvocationHandlerImpl(…);
  2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
    Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
  3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
    Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
  4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
    Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

缺点:jdk动态代理,必须是面向接口,目标业务类必须实现接口

// 每次生成动态代理类对象时,实现了InvocationHandler接口的调用处理器对象
public class InvocationHandlerImpl implements InvocationHandler {

   private Object target;// 这其实业务实现类对象,用来调用具体的业务方法
   
   // 通过构造函数传入目标对象
   public InvocationHandlerImpl(Object target) {
      this.target = target;
   }
   
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      Object result = null;
      System.out.println("调用开始处理");
      result = method.invoke(target, args);
      System.out.println("调用结束处理");
      return result;
   }
   
   public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
       IllegalAccessException, IllegalArgumentException, InvocationTargetException {
     // 被代理对象
      IUserDao userDao = new UserDao();
     InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDao);
     ClassLoader loader = userDao.getClass().getClassLoader();
     Class<?>[] interfaces = userDao.getClass().getInterfaces();
     // 主要装载器、一组接口及调用处理动态代理实例
      IUserDao newProxyInstance = (IUserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);
      newProxyInstance.save();
   }
}
Cglib 、javaassist(字节码操作库)

原理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

什么是CGLIB动态代理
使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码

public class CglibProxy implements MethodInterceptor {
   Private Object targetObject;
   // 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理
   public Object getInstance(Object target) {
      // 设置需要创建子类的类
      this.targetObject = target;
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(target.getClass());
      enhancer.setCallback(this);
      return enhancer.create();
   }
 
   public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
      System.out.println("开启事物");
      Object result = proxy.invoke(targetObject, args);
      System.out.println("关闭事物");
      // 返回代理对象
      return result;
   }
   public static void main(String[] args) {
      CglibProxy cglibProxy = new CglibProxy();
      UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDao());
      userDao.save();
   }
}
CGLIB动态代理与JDK动态区别

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
Spring中。

  1. 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
  2. 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
  3. 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。

AOP编程使用
XML方式实现AOP

Xml实现aop编程:
1)引入jar文件【aop 相关jar, 4个】
2)引入aop名称空间
3)aop 配置
配置切面类(重复执行代码形成的类)
aop配置
拦截哪些方法 / 拦截到方法后应用通知代码

<beansxmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"
  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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
  <!-- dao实例 -->
  <bean id="userService" class="com.itmayiedu.service.UserService"></bean>
  <!-- 切面类 -->
   <bean id="aop" class="com.itmayiedu.aop2.AopLog2"></bean>
  <!-- Aop配置 -->
  <aop:config>
     <!-- 定义一个切入点表达式:拦截哪些方法 -->
      <aop:pointcut expression="execution(* com.itmayiedu.service.UserService.*(..))" id="pt"/>
     <!-- 切面 -->
     <aop:aspect ref="aop">
       <!-- 环绕通知 -->
         <aop:around method="around" pointcut-ref="pt"/>
       <!-- 前置通知:在目标方法调用前执行 -->
         <aop:before method="begin" pointcut-ref="pt"/>
         <!-- 后置通知: -->
         <aop:after method="after" pointcut-ref="pt"/>
         <!-- 返回后通知 -->
         <aop:after-returning method="afterReturning" pointcut-ref="pt"/>
         <!-- 异常通知 -->
         <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
      </aop:aspect>
   </aop:config>
</beans>

public class AopLog2 {
   // 前置通知
   publicvoid begin() {
      System.out.println("前置通知");
   }
   // 后置通知
   publicvoid commit() {
      System.out.println("后置通知");
   }
   // 运行通知
   publicvoid returning() {
      System.out.println("运行通知");
   }
   // 异常通知
   publicvoid afterThrowing() {
      System.out.println("异常通知");
   }
   // 环绕通知
   publicvoid around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
      System.out.println("环绕通知开始");
      proceedingJoinPoint.proceed();
      System.out.println("环绕通知结束");
   }
}
注解版本实现AOP
/*
 * AOP:【动态代理】
 *     指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式; 
 * 1、导入aop模块;Spring AOP:(spring-aspects)
 * 2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
 * 3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
 *     通知方法:
 *        前置通知(@Before):logStart:在目标方法(div)运行之前运行
 *        后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
 *        返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
 *        异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
 *        环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
 * 4、给切面类的目标方法标注何时何地运行(通知注解);
 * 5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
 * 6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
 * [7]、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
 *     在Spring中很多的 @EnableXXX;
 * 
 * 三步:
 *   1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
 *   2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
 *  3)、开启基于注解的aop模式;@EnableAspectJAutoProxy
*/

MathCalculator业务类

public class MathCalculator {
  public int div(int i,int j){
     System.out.println("MathCalculator...div...");
     return i/j; 
  }
}

LogAspects切面类

/**
 * 切面类
 * @Aspect: 告诉Spring当前类是一个切面类
 */
@Aspect
public class LogAspects {
  //抽取公共的切入点表达式
  //1、本类引用
  //2、其他的切面引用
  @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
  public void pointCut(){};
  
  //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
  @Before("pointCut()")
  public void logStart(JoinPoint joinPoint){
     Object[] args = joinPoint.getArgs();
     System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
  }
  
  @After("com.atguigu.aop.LogAspects.pointCut()")
  public void logEnd(JoinPoint joinPoint){
     System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
  }
  
  //JoinPoint一定要出现在参数表的第一位
  @AfterReturning(value="pointCut()",returning="result")
  public void logReturn(JoinPoint joinPoint,Object result){
     System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
  }
  
  @AfterThrowing(value="pointCut()",throwing="exception")
  public void logException(JoinPoint joinPoint,Exception exception){
     System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
  }
}
 

MainConfigOfAOP配置类

@EnableAspectJAutoProxy注解类似于
<!-- 开启基于注解版的切面功能 -->
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
 
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
   
  //业务逻辑类加入容器中
  @Bean
  public MathCalculator calculator(){
     return new MathCalculator();
  }
  //切面类加入到容器中
  @Bean
  public LogAspects logAspects(){
     return new LogAspects();
  }
}

测试类

public class IOCTest_AOP {
  
  @Test
  public void test01(){
     AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
     
     //1、不要自己创建对象
//   MathCalculator mathCalculator = new MathCalculator();
//   mathCalculator.div(1, 1);
     MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
     mathCalculator.div(1, 0);
     applicationContext.close();
  }
}

@EnableAspectJAutoProxy
AOP原理:【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】
/*
 *     @EnableAspectJAutoProxy;
 * 1、@EnableAspectJAutoProxy是什么?
 *     @Import(AspectJAutoProxyRegistrar.class):给容器中导入AspectJAutoProxyRegistrar
 *        利用AspectJAutoProxyRegistrar自定义给容器中注册bean;BeanDefinetion
 *        internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
 * 
 *     给容器中注册一个AnnotationAwareAspectJAutoProxyCreator;
 * 
 * 2、 AnnotationAwareAspectJAutoProxyCreator:
 *     AnnotationAwareAspectJAutoProxyCreator
 *        ->AspectJAwareAdvisorAutoProxyCreator
 *          ->AbstractAdvisorAutoProxyCreator
 *             ->AbstractAutoProxyCreator
 *                  implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
 *               关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory
 * 
 * AbstractAutoProxyCreator.setBeanFactory()
 * AbstractAutoProxyCreator.有后置处理器的逻辑;
 * 
 * AbstractAdvisorAutoProxyCreator.setBeanFactory()-》initBeanFactory()
 * AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
 *
 * 流程:
 *     1)、传入配置类,创建ioc容器
 *     2)、注册配置类,调用refresh()刷新容器;
 *     3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;
 *        1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
 *        2)、给容器中加别的BeanPostProcessor
 *        3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
 *        4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
 *        5)、注册没实现优先级接口的BeanPostProcessor;
 *        6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
 *          创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
 *          1)、创建Bean的实例
 *          2)、populateBean;给bean的各种属性赋值
 *          3)、initializeBean:初始化bean;
 *               1)、invokeAwareMethods():处理Aware接口的方法回调
 *               2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
 *               3)、invokeInitMethods();执行自定义的初始化方法
 *               4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
 *          4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
 *        7)、把BeanPostProcessor注册到BeanFactory中;
 *          beanFactory.addBeanPostProcessor(postProcessor);
*/

AOP编程应用场景
事务控制分类
编程式事务控制

自己手动控制事务,就叫做编程式事务控制。
Jdbc代码:
Conn.setAutoCommite(false); // 设置手动控制事务
Hibernate代码:
Session.beginTransaction(); // 开启一个事务
【细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制】
(比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚.)

声明式事务控制

Spring提供了对事务的管理, 这个就叫声明式事务管理。
Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦。
Spring声明式事务管理,核心实现就是基于Aop。
【粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。】
(因为aop拦截的是方法。)

Spring声明式事务管理器类:
Jdbc技术:DataSourceTransactionManager
Hibernate技术:HibernateTransactionManager

手写Spring事务框架
编程事务实现

所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
使用编程事务实现,手动事务 begin、commit、rollback

@Component
public class TransactionUtils {
   @Autowired
   private DataSourceTransactionManager dataSourceTransactionManager;
  // 开启事务
   public TransactionStatus begin() {
     TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
     return transaction;
  }
  // 提交事务
   publicvoid commit(TransactionStatus transactionStatus) {
     dataSourceTransactionManager.commit(transactionStatus);
  }
  // 回滚事务
   publicvoidrollback(TransactionStatus transactionStatus) {
     dataSourceTransactionManager.rollback(transactionStatus);
  }
}

@Service
publicclass UserService {
  @Autowired
  private UserDao userDao;
  @Autowired
  private TransactionUtils transactionUtils;
  publicvoid add() {
     TransactionStatus transactionStatus = null;
     try {
       transactionStatus = transactionUtils.begin();
       userDao.add("wangmazi", 27);
       inti = 1 / 0;
       System.out.println("我是add方法");
       userDao.add("zhangsan", 16);
       transactionUtils.commit(transactionStatus);
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       if (transactionStatus != null) {
          transactionStatus.rollbackToSavepoint(transactionStatus);
       }
     }
  }
}
AOP技术封装手动事务
@Component
@Aspect
public class AopTransaction {
  @Autowired
  private TransactionUtils transactionUtils;
  // // 异常通知
   @AfterThrowing("execution(* com.itmayiedu.service.UserService.add(..))")
  publicvoid afterThrowing() {
     System.out.println("程序已经回滚");
      // 获取程序当前事务进行回滚
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  }
  // 环绕通知
   @Around("execution(* com.itmayiedu.service.UserService.add(..))")
  publicvoid around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
     System.out.println("开启事务");
      TransactionStatus begin = transactionUtils.begin();
     proceedingJoinPoint.proceed();
     transactionUtils.commit(begin);
     System.out.println("提交事务");
   }
}

使用事务注意事项
事务是程序运行如果没有错误,会自动提交事物,如果程序运行发生异常,则会自动回滚。
如果使用了try捕获异常时.一定要在catch里面手动回滚。
事务手动回滚代码
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

手写Spring注解版本事务

注解
Jdk1.5新增新技术,注解。很多框架为了简化代码,都会提供有些注解。可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件。
注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
注解分类:内置注解(也成为元注解jdk 自带注解)、自定义注解(Spring框架)
什么是内置注解
(1) @SuppressWarnings 再程序前面加上可以在javac编译中去除警告–阶段是SOURCE
(2) @Deprecated 带有标记的包,方法,字段说明其过时----阶段是SOURCE
(3)@Override 打上这个标记说明该方法是将父类的方法重写–阶段是SOURCE
@Override 案例演示

@Override
  public String toString() {
     return null;
  }

@Deprecated案例演示

new Date().parse("");

@SuppressWarnings 案例演示

@SuppressWarnings({ "all" })
  Public void save() {
     java.util.List list = new ArrayList();
  }

实现自定义注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:

  1. @Target
    @Target说明了Annotation所修饰的对象范围:Annotation可被用于packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

    CONSTRUCTOR:用于描述构造器
    FIELD:用于描述域
    LOCAL_VARIABLE:用于描述局部变量
    METHOD:用于描述方法
    PACKAGE:用于描述包
    PARAMETER:用于描述参数
    TYPE:用于描述类、接口(包括注解类型)或enum声明

  2. @Retention
    表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

  3. @Documented

  4. @Inherited

使用@interface 定义注解。


@Target(value = { ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
Public @interface AddAnnotation {
   int userId() default 0;
   String userName() default "默认名称";
   String[] arrays();
}
反射读取注解信息
Public static void main(String[] args) throws ClassNotFoundException {
    Class classInfo = Class.forName("com.itmayiedu.entity.User");
    // 获取到所有方法
    Method[] methods = classInfo.getDeclaredMethods();
    for (Method method : methods) {
       System.out.println(method);
       AddAnnotation declaredAnnotation = method.getDeclaredAnnotation(AddAnnotation.class);
       if (declaredAnnotation == null) {
          // 结束本次循环
          continue;
       }
       // 获取userId
       intuserId = declaredAnnotation.userId();
       System.out.println("userId:" + userId);
       // 获取userName
       String userName = declaredAnnotation.userName();
       System.out.println("userName:" + userName);
       // 获取arrays
       String[] arrays = declaredAnnotation.arrays();
       for (String str : arrays) {
          System.out.println("str:" + str);
       }
    }
 }
 

自定义事务注解

//编程事务(需要手动begin 手动回滚手都提交)
@Component()
@Scope("prototype") // 设置成原型解决线程安全
publicclass TransactionUtils {
   private TransactionStatus transactionStatus;
   // 获取事务源
   @Autowired
   private DataSourceTransactionManager dataSourceTransactionManager;
  // 开启事务
   public TransactionStatus begin() {
     transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
     returntransactionStatus;
  }
  // 提交事务
   publicvoid commit(TransactionStatus transaction) {
     dataSourceTransactionManager.commit(transaction);
  }
  // 回滚事务
   publicvoid rollback() {
     System.out.println("rollback");
     dataSourceTransactionManager.rollback(transactionStatus);
  }
}

@Component
@Aspect
public class AopTransaction {

   @Autowired
   Private TransactionUtils transactionUtils;
   
   @AfterThrowing("execution(* com.itmayiedu.service.*.*.*(..))")
   public void afterThrowing() throws NoSuchMethodException, SecurityException {
      // isRollback(proceedingJoinPoint);
      System.out.println("程序发生异常");
      // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      // TransactionStatus currentTransactionStatus =TransactionAspectSupport.currentTransactionStatus();
      // System.out.println("currentTransactionStatus:" + currentTransactionStatus);
      transactionUtils.rollback();
   }
   
   // // 环绕通知 在方法之前和之后处理事情
   @Around("execution(* com.itmayiedu.service.*.*.*(..))")
   Public void  around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
      // 调用方法之前执行
      TransactionStatus transactionStatus = begin(proceedingJoinPoint);
      proceedingJoinPoint.proceed();// 代理调用方法 注意点: 如果调用方法抛出异常不会执行后面代码
      // 调用方法之后执行
      commit(transactionStatus);
   }
   
   public TransactionStatus begin(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
      // // 判断是否有自定义事务注解
      ExtTransaction declaredAnnotation = getExtTransaction(pjp);
      if (declaredAnnotation == null) {
         return null;
      }
      // 如果有自定义事务注解,开启事务
      System.out.println("开启事务");
      TransactionStatus transactionStatu = transactionUtils.begin();
      Return transactionStatu;
   }
   public void commit(TransactionStatus transactionStatu) {
      if (transactionStatu != null) {
         // 提交事务
         System.out.println("提交事务");
         transactionUtils.commit(transactionStatu);
      }
   }
   public ExtTransaction getExtTransaction(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
      // 获取方法名称
      String methodName = pjp.getSignature().getName();
      // 获取目标对象
      Class<?>  classTarget = pjp.getTarget().getClass();
      // 获取目标对象类型
      Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
      // 获取目标对象方法
      Method objMethod = classTarget.getMethod(methodName, par);
      // // 判断是否有自定义事务注解
      ExtTransaction  declaredAnnotation = objMethod.getDeclaredAnnotation(ExtTransaction.class);
      if (declaredAnnotation == null) {
         System.out.println("您的方法上,没有加入注解!");
         Return null;
      }
      Return declaredAnnotation;
   }
   // 回滚事务
   public void isRollback(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
      // // 判断是否有自定义事务注解
      ExtTransaction declaredAnnotation = getExtTransaction(pjp);
      if (declaredAnnotation != null) {
         System.out.println("已经开始回滚事务");
         // 获取当前事务 直接回滚
         TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
         return;
      }
   }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值