您的位置:首页 > 其它

自定义注解简单实现

2019-05-26 15:49 453 查看
[code]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 {

}
[code]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);
}

}
[code]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记住
* 记一辈子没用的
* 我们写是写几个步骤核心的
* 这是我要给你们讲的
* 这理不理解
* 没必要记住
* 我之前自己下去找这个方法的时候
* 我会找很长时间的
* 那这个
3ff7
方法看不看得懂什么意思
* 获取你代理对象的方法
* 我把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;
}

}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: