为了避免使用方法直接显示的参数传递,我们可以采用 ThreadLocal 实现上下文来存储和获取参数,假设我们现在需要实现提现上下文 WithdrawContext
,首先定义一个上下文类 WithdrawContext
,并定义对应上下文管理器 WithdrawManager
:
1 2 3 4 5 6 7 8
| @Data @Builder @NoArgsConstructor @AllArgsConstructor public class WithdrawContext { private String withdrawId; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class WithdrawContextManager {
private static final ThreadLocal<WithdrawContext> THREAD_LOCAL = new InheritableThreadLocal<>();
public static void setContext(WithdrawContext context) { THREAD_LOCAL.set(context); }
public static WithdrawContext getContext() { return THREAD_LOCAL.get(); }
public static void removeContext() { THREAD_LOCAL.remove(); } }
|
为了简化开发,我们可以采用切面来初始化和销毁上下文,首先我们定义如下注解,并采用 AOP 切面来针对声明有对应注解的方法进行切面处理:
1 2 3 4 5 6
| @Target({ElementType.CONSTRUCTOR, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WithdrawContextHolder { }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Component @Aspect public class WithdrawContextAspect {
@Pointcut(value = "@annotation(com.shoto.threadlocal.WithdrawContextHolder)") public void pointCut() {
}
@Around("pointCut()") public Object invokeAround(ProceedingJoinPoint joinPoint) throws Throwable { try { WithdrawContextManager.removeContext(); WithdrawContextManager.setContext(new WithdrawContext()); return joinPoint.proceed(); } finally { WithdrawContextManager.removeContext(); } } }
|
至此,我们便可以在 Service 方法上进行使用,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Service public class WithdrawServiceImpl implements WithdrawService {
@Override @WithdrawContextHolder public String getWithdrawId() { WithdrawContext withdrawContext = WithdrawContextManager.getContext(); withdrawContext.setWithdrawId(UUID.randomUUID().toString()); return queryWithdraw(); }
private String queryWithdraw() { WithdrawContext withdrawContext = WithdrawContextManager.getContext(); return withdrawContext.getWithdrawId(); } }
|