自定义注解简单实现

博客主要围绕自定义注解的简单实现展开,虽未给出具体内容,但可知聚焦于自定义注解这一信息技术领域内容,通过相关操作达成简单实现的目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.learn.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 事务注解 设置传播行为
/**
 * 在前面加个Ext
 * 这个注解是干嘛的
 * 你们一定要知道
 * 它是事务注解
 * 定义好了之后
 * 在这里面其实有这几个方法
 * 但是我今天可能用不到这几个方法
 * 你们下去自己去封装
 * 设置传播行为
 * 具体怎么实现呢
 * 方法我就不写了
 * 你们自己写
 * 我们看看源码里面是怎么写的
 * 你们看一下
 * 源码里面加了拦截权限
 * 把这些我们也copy过来
 * 因为这个代码你们看的懂
 * { ElementType.METHOD, ElementType.TYPE }
 * 我们可以写这两个
 * 可以在方法上面加上这个注解
 * 可以在类上加上这个注解
 * 我们不允许在类上用
 * 我们这个注解不允许在类上面用
 * 只允许在方法上去玩了
 * @Retention(RetentionPolicy.RUNTIME)
 * 这个写完之后我们再写第二步
 * 跟着我的步骤来
 * 封装手动事务
 * 这个是我昨天写过的
 * 是不是这样的
 * 我写过的话就不写了
 * 因为待会我们就会用到这段代码的
 * 
 * 
 * 
 * @author Leon.Sun
 *
 */
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtTransaction {

}
package com.learn.transaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

// 编程事务(需要手动begin 手动回滚 手都提交)
/**
 * 我们还原成昨天的
 * 否则到时会绕的
 * 这个是手动获取事务
 * 手动begin
 * 手动commit和手动rollback
 * 这代码你们有没有印象
 * 昨天讲过的
 * 我特意讲过这段代码的
 * 还手写过这个事务的
 * 是不是这样的
 * 这个代码看不看得懂
 * 这个代码不难
 * 只要别人调用begin方法我就去开启一个事务
 * 如果要是调用commit和rollback
 * 去回滚或者提交
 * 现在看应该能够看得懂
 * 这个昨天已经讲过的
 * 这个其实没有什么难的
 * 你们学过事务都知道的
 * 然后我们接着再怎么做呢
 * 我们核心是在具体如何扫包
 * 具体如何扫包的话
 * 那么这里面我不是要写一个AOP了
 * 
 * 
 * 
 * @author Leon.Sun
 *
 */
@Component
//@Scope("prototype") // 每个事务都是新的实例 目的解决线程安全问题 多例子
public class TransactionUtils {

	// 全局接受事务状态
	private TransactionStatus transactionStatus;
	// 获取事务源
	@Autowired
	private DataSourceTransactionManager dataSourceTransactionManager;

	// 开启事务
	public TransactionStatus begin() {
		transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
		return transactionStatus;
	}

	// 提交事务
	public void commit(TransactionStatus transaction) {
		dataSourceTransactionManager.commit(transaction);
	}

	// 回滚事务
	public void rollback() {
		dataSourceTransactionManager.rollback(transactionStatus);
	}

}
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;

//  自定义事务注解具体实现
/**
 * 我们自定义的事务注解具体实现
 * 然后在这里写一下
 * 加上切面编程@Aspect
 * 在这里面怎么写呢
 * 在这里还要加上@Component
 * 让他注入到Spring的容器里面去
 * 这步写完了之后
 * 我说过的
 * 你们说一下这是一个什么通知啊
 * 就是这个拦截方法的时候
 * 拦截所有方法的情况下
 * 什么通知
 * 你们想一想
 * 就是这步他能用什么通知
 * 肯定是环绕通知
 * 记住肯定是环绕通知
 * 不可能用到其他通知的
 * 肯定是用环绕
 * 那我把环绕代码copy过来好吧
 * 我就不去写了
 * 因为我昨天讲过了
 * 是不是这样的
 * 再写的话就比较浪费时间了
 * 在这边说一下
 * 
 * 
 * 
 * @author Leon.Sun
 *
 */
@Aspect
@Component
public class AopExtTransaction {
	// 一个事务实例子 针对一个事务
	/**
	 * 我们把自定义的手动事务copy过来
	 * 再去@Autowired一下
	 * 
	 */
	@Autowired
	private TransactionUtils transactionUtils;

	// 使用异常通知进行 回滚事务
	/**
	 * 我们现在是写框架的话
	 * 把它写成全部的
	 * "execution(* com.learn.service.*.*.*(..))"
	 * 这是我要和你们去讲一下的
	 * 全部怎么写
	 * service.*.*.*(..)
	 * 这个都理解吧
	 * 我就不去说了
	 * 我们找那个包下面的呢
	 * 我们找这个包下面的
	 * com.learn.service
	 * 这步写完了之后
	 * 这边的代码就有点麻烦了
	 * 怎么麻烦了
	 * 这也是非常核心的代码
	 * 
	 * 
	 */
	@AfterThrowing("execution(* com.learn.service.*.*.*(..))")
	public void afterThrowing() {
		// 获取当前事务进行回滚
		// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		transactionUtils.rollback();
	}

	// 环绕通知 在方法之前和之后处理事情
	/**
	 * 我们把这段代码copy过来
	 * 拦截到方法之后你们说一下
	 * 我这边就直接口说这个步骤
	 * 步骤答出来可能会好理解点
	 * 要不然直接这样改的话可能会比较绕
	 * 首先获取到代理对象的方法
	 * 第二步干嘛呢
	 * 获取该方法上是否加上注解
	 * 是不是这样的
	 * 然后到第三步的时候
	 * 你们想想到第三步怎么做
	 * 如果存在事务注解
	 * 是不是开启这个事务
	 * 然后到第四步干嘛
	 * 调用目标代理对象方法
	 * 到第五步怎么做你想想
	 * 第五步的时候代理对象方法调用完毕的情况下
	 * 他怎么做
	 * 想想怎么做
	 * 判断该方法上是否加上注解
	 * 这个我昨天已经说过了
	 * 然后同样道理
	 * 第六步什么样的呢
	 * 如果存在注解
	 * 你看我是写的非常详细的
	 * 如果存在注解
	 * 怎么样呢
	 * 是不是提交事务
	 * 我们可以先把四步先写出来
	 * 获取目标代理方法这个比较麻烦
	 * 大家写的时候可以直接去copy
	 * 因为这里面的代码可能会比较多
	 * 然后你们不要看我们文档里面的
	 * 有些方法没有必要记下来
	 * 你只要知道怎么做就行了
	 * 这是我要和你们说的
	 * 所以这边我和你们说一下
	 * 这个你们不要去记
	 * 
	 * 
	 * 
	 * 
	 * @param pjp
	 * @throws Throwable
	 */
	@Around("execution(* com.learn.service.*.*.*(..))")
	public void around(ProceedingJoinPoint pjp) throws Throwable {

		// 1.获取该方法上是否加上注解
		ExtTransaction extTransaction = getMethodExtTransaction(pjp);
		/**
		 * 我们拿到事务注解之后呢
		 * 
		 */
		TransactionStatus transactionStatus = begin(extTransaction);
		// 2.调用目标代理对象方法
		/**
		 * 这个方法直接调用目标代理对象
		 * 待会我们的代码都会做重构
		 * 
		 */
		pjp.proceed();
		// 3.判断该方法上是否就上注解
		commit(transactionStatus);
	}

	private TransactionStatus begin(ExtTransaction extTransaction) {
		if (extTransaction == null) {
			return null;
		}
		// 2.如果存在事务注解,开启事务
		/**
		 * 开启事务是不是到这里来了
		 */
		return transactionUtils.begin();
	}

	/**
	 * 判断是否加上注解了
	 * 待会我会把整个代码做个重构
	 * 重构的话看起来就会舒服多了
	 * 大家先忍耐一下
	 * 做完了做重构
	 * 否则你们不知道重构是怎么来的
	 * 如果transactionStatus等于null说明了什么问题
	 * 你们想一想
	 * 我不需要给他开启事务
	 * 那我就不做任何操作
	 * 
	 * 
	 * @param transactionStatus
	 */
	private void commit(TransactionStatus transactionStatus) {
		/**
		 * 所以判断不等于null的情况下
		 * 走到这一步的话
		 * 在方法上加上事务的注解了
		 * 是不是这样的
		 * 这个时候我怎么办
		 * transactionUtils.commit
		 * 
		 */
		if (transactionStatus != null) {
			/**
			 * 5.如果存在注解,提交事务
			 * 去提交这样的一个事务
			 */
			transactionUtils.commit(transactionStatus);
		}

	}

	// 获取方法上是否存在事务注解
	/**
	 * 这段代码直接copy过来
	 * 我先给你们写一下
	 * 因为这段代码比较长
	 * 而且写得话太浪费时间了
	 * 而且这段代码也没有什么意义
	 * 这段代码其实是怎么样的一个目的
	 * 给大家说一下
	 * 你们猜也猜得到干嘛用的呢
	 * 相当于通过你的切入点
	 * 获取目标代理对象方法
	 * 是不是这样的
	 * 我在下去写代码的时候
	 * 你知道我是怎么知道这API的吗
	 * 这也是你们要记住的思路
	 * 没有必要把任何代码都记住
	 * 什么意思呢
	 * 这段代码我开始也不知道通过这段代码可以获取代理对象的方法
	 * 我怎么做呢
	 * 先脑海中有这个思路
	 * 然后我直接百度去找
	 * AOP里面是怎么去获取代理对象的方法
	 * 就是这样的
	 * 明白这个意思没有
	 * 千万别说我下去把API记住
	 * 记一辈子没用的
	 * 我们写是写几个步骤核心的
	 * 这是我要给你们讲的
	 * 这理不理解
	 * 没必要记住
	 * 我之前自己下去找这个方法的时候
	 * 我会找很长时间的
	 * 那这个方法看不看得懂什么意思
	 * 获取你代理对象的方法
	 * 我把userServiceImpl的add给AOP进行管理的情况下
	 * 我们就可以去获取这个方法
	 * 这个都是能够看得懂的
	 * 如果这个看不懂那就说明有问题了
	 * 获取到之后
	 * 然后怎么做呢
	 * 
	 * 
	 * @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();
		/**
		 * 获取目标对象方法
		 */
		Method objMethod = classTarget.getMethod(methodName, par);
		/**
		 * 就是获取一下这个方法上有没有加上@ExtTransaction注解
		 * 是不是这样的
		 * 然后这个代码写完了之后呢
		 * 然后ExtTransaction.class
		 * 然后我们这边拿到这个事务注解
		 * 
		 */
		ExtTransaction extTransaction = objMethod.getDeclaredAnnotation(ExtTransaction.class);
		return extTransaction;
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值