重构自定义注解代码

    xiaoxiao2025-03-23  23

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.learn</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/javassist/javassist --> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <!-- 引入Spring-AOP等相关Jar --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>3.0.6.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.1_2</version> </dependency> <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> </dependencies> </project> <beans xmlns="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" xmlns:tx="http://www.springframework.org/schema/tx" 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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- aop的扫包注解是有的 --> <context:component-scan base-package="com.learn"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/day20"></property> <property name="user" value="root"></property> <property name="password" value="123456"></property> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 我们把原生的事务注解删掉 --> <!-- <tx:annotation-driven transaction-manager="dataSourceTransactionManager" /> --> </beans> package com.learn.aop; import java.lang.reflect.Method; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.TransactionStatus; import com.learn.annotation.ExtTransaction; import com.learn.transaction.TransactionUtils; /** * 我们把代码重构一下 * 要不然会比较麻烦 * * @author Leon.Sun * */ @Aspect @Component public class AopExtTransaction { // 一个事务实例子 针对一个事务 @Autowired private TransactionUtils transactionUtils; // 使用异常通知进行 回滚事务 /** * 我们还有个异常通知没有封装完 * 异常我们要单独讲 * 所以我们先讲这个 * * */ @AfterThrowing("execution(* com.learn.service.*.*.*(..))") public void afterThrowing() { // 获取当前事务进行回滚 // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); transactionUtils.rollback(); } // 环绕通知 在方法之前和之后处理事情 /** * 我们要把这段代码重构一下 * 所以这个时候我们怎么做呢 * 因为看那么长的代码我看起来也痛苦 * 这样的话我们就比较简单了 * * 我把所有的方法都给抽取出来 * 该比较舒服一点 * 有没有什么疑问 * 这应该没有什么疑问 * 是不是这样的 * 所以在这边讲一下 * 你们下去写代码的时候 * 就是别人看的时候也知道 * 获取这样的一个注解 * 然后进行begin * * * * @param pjp * @throws Throwable */ @Around("execution(* com.learn.service.*.*.*(..))") public void around(ProceedingJoinPoint pjp) throws Throwable { /** * 1.获取该方法上是否加上注解 * 我们拿到事务注解 * 第一步获取目标代理对象 * * 首先进入到AOP代码里面去了 * 看到没有 * 进入到AOP代码里面去了之后 * 获取这个方法有没有加这个注解 * */ ExtTransaction extTransaction = getMethodExtTransaction(pjp); /** * 这边只要调用它就行了 * 看起来就轻松一点 * 然后把这个状态传进来 * 直接传入注解里面去 * 在这里我们是可以拿返回结果的 * 然后这边就是状态了 * * 有注解的时候我们在begin方法里面判断一下 * 判断一下他到底有没有这个注解 * 这个注解不等于null * 不等于null的情况下 * * 开启完事务之后 * * */ TransactionStatus transactionStatus = begin(extTransaction); // 2.调用目标代理对象方法 /** * 就会调用我们的目标代理对象方法 * 会走到我们的add方法里面来 * */ pjp.proceed(); // 3.判断该方法上是否就上注解 /** * 然后在这里就直接判断不等于null的情况下 * 然后整个我就封装的比较简单 * 我全部抽出来 * 不执行的情况就走异常通知的 * 大概就讲完了 * 有没有什么疑问呢 * 就这样封装完了 * * 是不是走commit * 你的状态就不为空 * 走到里面去 * 不等于null的情况我就提交事务 * * */ commit(transactionStatus); } /** * 然后我再把它封装一下 * 这样看起来不是很爽 * 代码全部放在这里面去 * 其实这段代码也要封装一下 * * * * @param extTransaction * @return */ private TransactionStatus begin(ExtTransaction extTransaction) { System.out.println("开启事务......................."); /** * 没加事务就不会走到这里面去 * 就不会begin * 也不会commit的 * 如果为null就直接return掉 * return null就行了 * * 走到这里判断一下 * 判断你有没有加注解 * 如果加了注解的情况下就开启这么一个事务 * 是不是这样的 * 你看一下 * 是不是开启事务 * * */ if (extTransaction == null) { return null; } // 2.如果存在事务注解,开启事务 /** * 我喜欢这样去写 * 看着舒服一点 * * 不等于null就开启这个事务了 * 是不是这样的 * * */ return transactionUtils.begin(); } /** * 把这个封装完 * 我就封装的比较加简单 * 尤其是写这样的代码 * * * @param transactionStatus */ private void commit(TransactionStatus transactionStatus) { System.out.println("提交事务......................."); /** * 这里通过状态判断会好一点 * 如果transactionStatus不等于null的情况下 * 我再次提交这个事务 * 因为只有当他有状态的情况下 * 才有这样的一个权限 * 待会我们演示一把 * 只要transactionStatus他不为null的情况下 * 我才会提交 * 如果没有为空说明有事务 * 如果为空 * 那就根本没有走到里面去 * 在这里就直接走完就行了 * 没必要去提交事务了 * 是不是这样的 * 这段代码就大体的这样写了以后 * 这个时候我就说一下 * 因为之前我都是封装起来的 * 会有的 * 我待会演示就知道了 * 我待会讲你就知道 * 没加事务就不会走到这里面去 * */ if (transactionStatus != null) { /** * 如果他不等于null的情况下的时候 * 是不是这样的 * */ transactionUtils.commit(transactionStatus); } } /** * 我们定义一个方法 * 获取这个注解getMethodExtTransaction * 获取方法上的一个注解 * 看有没有这个注解吗 * 我在上面写个注释 * 获取方法上是否存在事务注解 * 然后这里面怎么写呢 * 我们得重构过来 * 因为代码太多了 * 看起来比较痛苦 * 是不是同样要传入ProceedingJoinPoint切入点过来 * 是不是写完了 * 然后我们把异常抛出去 * * * * @param pjp * @return * @throws NoSuchMethodException * @throws SecurityException */ private ExtTransaction getMethodExtTransaction(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException { String methodName = pjp.getSignature().getName(); Class<?> classTarget = pjp.getTarget().getClass(); Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes(); /** * 我们看一下方法是哪一个 * 是不是add方法 * * */ Method objMethod = classTarget.getMethod(methodName, par); /** * 然后看一下add方法有没有注解 * 是不是有的 * 有没有加上注解 * 是没有没有提交 * 是不是有这样的一个注解 * 有这样的注解的话 * * */ ExtTransaction extTransaction = objMethod.getDeclaredAnnotation(ExtTransaction.class); return extTransaction; } } package com.learn.service; //user 服务层 public interface UserService { public void add(); public void del(); } package com.learn.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.learn.annotation.ExtTransaction; import com.learn.dao.UserDao; import com.learn.service.UserService; import com.learn.transaction.TransactionUtils; @Service public class UserServiceImpl implements UserService { @Autowired private TransactionUtils transactionUtils; @Autowired private UserDao userDao; /** * 这里加了一个事务注解 * 就开始事务 * * 我们加自定义的注解@ExtTransaction * 我们这里不要try * 因为我们要演示一下异常场景 * 异常通知我们会单独讲的 * 上面加个注解 * 我们自己写的这个 * 我们怎么判断我们的这个事务到底有没有成功呢 * 只要执行到userDao.add("test001", 20);之后 * 不要插入到数据库里面去 * 是不是肯定是对的 * 是不是这样的 * * */ // @Transactional // @ExtTransaction public void add() { userDao.add("test001", 20); // int i = 1/0; /** * 到这里的时候数据是不是没有 * 看到没有 * * 走过了之后是不是走完了 * 我们查一下有没有数据 * 没有吧 * 没有的话我们继续走 * * */ System.out.println("####################################"); /** * 走到这里 * 没有异常的情况下还是会回到AOP里面去 * 回到commit里面来 * * */ userDao.add("test002", 21); } /** * 这里没有加注解就不开启事务 * 那么最后怎么做呢 * * * * */ public void del() { System.out.println("del"); } } package com.learn; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.learn.service.UserService; public class Test001 { public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); UserService userService = (UserService) applicationContext.getBean("userServiceImpl"); userService.add(); } }

     

    最新回复(0)