refactor: 重构所有 rpc 组件的 SaTokenContext 上下文读写策略 & 删除二级上下文模块

This commit is contained in:
click33
2025-04-07 05:41:30 +08:00
parent c6a081ebf6
commit 3acc7bd7af
50 changed files with 526 additions and 585 deletions

View File

@@ -21,9 +21,7 @@ import cn.dev33.satoken.apikey.loader.SaApiKeyDataLoaderDefaultImpl;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaTokenConfigFactory;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.context.SaTokenContextDefaultImpl;
import cn.dev33.satoken.context.SaTokenContextForThreadLocal;
import cn.dev33.satoken.context.second.SaTokenSecondContext;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;
import cn.dev33.satoken.error.SaErrorCode;
@@ -148,7 +146,7 @@ public class SaManager {
}
/**
* 一级上下文 SaTokenContextContext
* 上下文 SaTokenContext
*/
private volatile static SaTokenContext saTokenContext;
public static void setSaTokenContext(SaTokenContext saTokenContext) {
@@ -166,42 +164,6 @@ public class SaManager {
return saTokenContext;
}
/**
* 二级上下文 SaTokenSecondContext
*/
private volatile static SaTokenSecondContext saTokenSecondContext;
public static void setSaTokenSecondContext(SaTokenSecondContext saTokenSecondContext) {
SaManager.saTokenSecondContext = saTokenSecondContext;
SaTokenEventCenter.doRegisterComponent("SaTokenSecondContext", saTokenSecondContext);
}
public static SaTokenSecondContext getSaTokenSecondContext() {
return saTokenSecondContext;
}
/**
* 获取一个可用的 SaTokenContext (按照一级上下文、二级上下文、默认上下文的顺序来判断)
* @return /
*/
public static SaTokenContext getSaTokenContextOrSecond() {
// s1. 一级Context可用时返回一级Context
if(saTokenContext != null) {
if(saTokenSecondContext == null || saTokenContext.isValid()) {
// 因为 isValid 是一个耗时操作所以此处假定二级Context为null的情况下无需验证一级Context有效性
// 这样可以提升6倍左右的上下文获取速度
return saTokenContext;
}
}
// s2. 一级Context不可用时判断二级Context是否可用
if(saTokenSecondContext != null && saTokenSecondContext.isValid()) {
return saTokenSecondContext;
}
// s3. 都不行,就返回默认的 Context
return SaTokenContextDefaultImpl.defaultContext;
}
/**
* 临时 token 认证模块
*/

View File

@@ -18,6 +18,7 @@ package cn.dev33.satoken.context;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.model.SaTokenContextModelBox;
/**
* Sa-Token 上下文处理器
@@ -30,37 +31,59 @@ import cn.dev33.satoken.context.model.SaStorage;
public interface SaTokenContext {
/**
* 获取当前请求的 Request 包装对象
* 初始化上下文
*
* @param req /
* @param res /
* @param stg /
*/
void setContext(SaRequest req, SaResponse res, SaStorage stg);
/**
* 清除化上下文
*/
void clearContext();
/**
* 判断当前上下文是否可用
*
* @return /
*/
boolean isValid();
/**
* 获取 Box 对象
*/
SaTokenContextModelBox getModelBox();
/**
* 获取当前上下文的 Request 包装对象
* @see SaRequest
*
* @return /
*/
SaRequest getRequest();
default SaRequest getRequest() {
return getModelBox().getRequest();
}
/**
* 获取当前请求的 Response 包装对象
* 获取当前上下文的 Response 包装对象
* @see SaResponse
*
* @return /
*/
SaResponse getResponse();
default SaResponse getResponse(){
return getModelBox().getResponse();
}
/**
* 获取当前请求的 Storage 包装对象
* 获取当前上下文的 Storage 包装对象
* @see SaStorage
*
* @return /
*/
SaStorage getStorage();
/**
* 判断:在本次请求中,此上下文是否可用。
* <p> 例如在部分 rpc 调用时, 一级上下文会返回 false这时候框架就会选择使用二级上下文来处理请求 </p>
*
* @return /
*/
default boolean isValid() {
return false;
default SaStorage getStorage(){
return getModelBox().getStorage();
}
}

View File

@@ -18,6 +18,7 @@ package cn.dev33.satoken.context;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.model.SaTokenContextModelBox;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenContextException;
@@ -44,6 +45,26 @@ public class SaTokenContextDefaultImpl implements SaTokenContext {
*/
public static final String ERROR_MESSAGE = "未能获取有效的上下文处理器";
@Override
public void setContext(SaRequest req, SaResponse res, SaStorage stg) {
throw new SaTokenContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
}
@Override
public void clearContext() {
throw new SaTokenContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
}
@Override
public boolean isValid() {
throw new SaTokenContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
}
@Override
public SaTokenContextModelBox getModelBox() {
throw new SaTokenContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
}
@Override
public SaRequest getRequest() {
throw new SaTokenContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);

View File

@@ -13,20 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.context.second;
package cn.dev33.satoken.context;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.model.SaTokenContextModelBox;
/**
* Sa-Token 二级Context - 基础接口
*
* <p> (利用继承机制实现区别 [ 一级Context ] [ 二级Context ] 的目的)
*
* @see SaTokenContext SaTokenContext 上下文处理器
* Sa-Token 上下文处理器次级实现只读上下文
*
* @author click33
* @since 1.28.0
* @since 1.42.0
*/
public interface SaTokenSecondContext extends SaTokenContext {
public interface SaTokenContextForReadOnly extends SaTokenContext {
@Override
default void setContext(SaRequest req, SaResponse res, SaStorage stg) {
}
@Override
default void clearContext() {
}
@Override
default SaTokenContextModelBox getModelBox() {
return null;
}
}

View File

@@ -18,6 +18,7 @@ package cn.dev33.satoken.context;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.model.SaTokenContextModelBox;
/**
* Sa-Token 上下文处理器 [ ThreadLocal 版本 ]
@@ -35,23 +36,23 @@ import cn.dev33.satoken.context.model.SaStorage;
public class SaTokenContextForThreadLocal implements SaTokenContext {
@Override
public SaRequest getRequest() {
return SaTokenContextForThreadLocalStorage.getRequest();
public void setContext(SaRequest req, SaResponse res, SaStorage stg) {
SaTokenContextForThreadLocalStaff.setModelBox(req, res, stg);
}
@Override
public SaResponse getResponse() {
return SaTokenContextForThreadLocalStorage.getResponse();
}
@Override
public SaStorage getStorage() {
return SaTokenContextForThreadLocalStorage.getStorage();
public void clearContext() {
SaTokenContextForThreadLocalStaff.clearModelBox();
}
@Override
public boolean isValid() {
return SaTokenContextForThreadLocalStorage.getBox() != null;
return SaTokenContextForThreadLocalStaff.getModelBoxOrNull() != null;
}
@Override
public SaTokenContextModelBox getModelBox() {
return SaTokenContextForThreadLocalStaff.getModelBox();
}
}

View File

@@ -18,6 +18,7 @@ package cn.dev33.satoken.context;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.context.model.SaTokenContextModelBox;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenContextException;
@@ -29,12 +30,12 @@ import cn.dev33.satoken.exception.SaTokenContextException;
* @author click33
* @since 1.16.0
*/
public class SaTokenContextForThreadLocalStorage {
public class SaTokenContextForThreadLocalStaff {
/**
* 基于 ThreadLocal [ Box 存储器 ]
*/
public static ThreadLocal<Box> boxThreadLocal = new InheritableThreadLocal<>();
public static ThreadLocal<SaTokenContextModelBox> modelBoxThreadLocal = new InheritableThreadLocal<>();
/**
* 初始化当前线程的 [ Box 存储器 ]
@@ -42,34 +43,34 @@ public class SaTokenContextForThreadLocalStorage {
* @param response {@link SaResponse}
* @param storage {@link SaStorage}
*/
public static void setBox(SaRequest request, SaResponse response, SaStorage storage) {
Box bok = new Box(request, response, storage);
boxThreadLocal.set(bok);
public static void setModelBox(SaRequest request, SaResponse response, SaStorage storage) {
SaTokenContextModelBox bok = new SaTokenContextModelBox(request, response, storage);
modelBoxThreadLocal.set(bok);
}
/**
* 清除当前线程的 [ Box 存储器 ]
*/
public static void clearBox() {
boxThreadLocal.remove();
public static void clearModelBox() {
modelBoxThreadLocal.remove();
}
/**
* 获取当前线程的 [ Box 存储器 ]
* @return /
*/
public static Box getBox() {
return boxThreadLocal.get();
public static SaTokenContextModelBox getModelBoxOrNull() {
return modelBoxThreadLocal.get();
}
/**
* 获取当前线程的 [ Box 存储器 ], 如果为空则抛出异常
* @return /
*/
public static Box getBoxNotNull() {
Box box = boxThreadLocal.get();
public static SaTokenContextModelBox getModelBox() {
SaTokenContextModelBox box = modelBoxThreadLocal.get();
if(box == null) {
throw new SaTokenContextException("未能获取有效的上下文").setCode(SaErrorCode.CODE_10002);
throw new SaTokenContextException("SaTokenContext 上下文尚未初始化").setCode(SaErrorCode.CODE_10002);
}
return box;
}
@@ -80,7 +81,7 @@ public class SaTokenContextForThreadLocalStorage {
* @return /
*/
public static SaRequest getRequest() {
return getBoxNotNull().getRequest();
return getModelBox().getRequest();
}
/**
@@ -89,7 +90,7 @@ public class SaTokenContextForThreadLocalStorage {
* @return /
*/
public static SaResponse getResponse() {
return getBoxNotNull().getResponse();
return getModelBox().getResponse();
}
/**
@@ -98,59 +99,8 @@ public class SaTokenContextForThreadLocalStorage {
* @return /
*/
public static SaStorage getStorage() {
return getBoxNotNull().getStorage();
return getModelBox().getStorage();
}
/**
* Box 临时内部类用于存储 [ SaRequestSaResponseSaStorage ] 三个包装对象
*
* @author click33
* @since 1.16.0
*/
public static class Box {
public SaRequest request;
public SaResponse response;
public SaStorage storage;
public Box(SaRequest request, SaResponse response, SaStorage storage){
this.request = request;
this.response = response;
this.storage = storage;
}
public SaRequest getRequest() {
return request;
}
public void setRequest(SaRequest request) {
this.request = request;
}
public SaResponse getResponse() {
return response;
}
public void setResponse(SaResponse response) {
this.response = response;
}
public SaStorage getStorage() {
return storage;
}
public void setStorage(SaStorage storage) {
this.storage = storage;
}
@Override
public String toString() {
return "Box [request=" + request + ", response=" + response + ", storage=" + storage + "]";
}
}
}

View File

@@ -0,0 +1,52 @@
package cn.dev33.satoken.context.model;
/**
* Box 盒子类,用于存储 [ SaRequest、SaResponse、SaStorage ] 三个包装对象
*
* @author click33
* @since 1.16.0
*/
public class SaTokenContextModelBox {
public SaRequest request;
public SaResponse response;
public SaStorage storage;
public SaTokenContextModelBox(SaRequest request, SaResponse response, SaStorage storage) {
this.request = request;
this.response = response;
this.storage = storage;
}
public SaRequest getRequest() {
return request;
}
public void setRequest(SaRequest request) {
this.request = request;
}
public SaResponse getResponse() {
return response;
}
public void setResponse(SaResponse response) {
this.response = response;
}
public SaStorage getStorage() {
return storage;
}
public void setStorage(SaStorage storage) {
this.storage = storage;
}
@Override
public String toString() {
return "Box [request=" + request + ", response=" + response + ", storage=" + storage + "]";
}
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.context.second;
/**
* Sa-Token 二级Context - 创建器
*
* @author click33
* @since 1.28.0
*/
@FunctionalInterface
public interface SaTokenSecondContextCreator {
/**
* 创建一个二级 Context 处理器
* @return /
*/
SaTokenSecondContext create();
}

View File

@@ -206,6 +206,16 @@ public class SaTokenConsts {
*/
public static final int SA_TOKEN_CONTEXT_FILTER_ORDER = -104;
/**
* RPC 框架权限过滤器的注册顺序
*/
public static final int RPC_PERMISSION_FILTER_ORDER = -30000;
/**
* RPC 框架上下文过滤器的注册顺序
*/
public static final int RPC_CONTEXT_FILTER_ORDER = -30005;
/**
* Content-Type key
*/