GlobalPlugin插件
GlobalPlugin插件是soul所有插件执行前,最先执行的一个插件。
作用是构建一个soul的上下文环境。
SoulContext
soul的上下文环境,由GlobalPlugin插件来构建
public class SoulContext implements Serializable {
/**
* is module data.
*/
private String module;
/**
* is method name .
*/
private String method;
/**
* is rpcType data. now we only support "http","dubbo","springCloud","sofa".
*/
private String rpcType;
/**
* httpMethod now we only support "get","post" .
*/
private String httpMethod;
/**
* this is sign .
*/
private String sign;
/**
* timestamp .
*/
private String timestamp;
/**
* appKey .
*/
private String appKey;
/**
* path.
*/
private String path;
/**
* the contextPath.
*/
private String contextPath;
/**
* realUrl.
*/
private String realUrl;
/**
* this is dubbo params.
*/
private String dubboParams;
/**
* startDateTime.
*/
private LocalDateTime startDateTime;
}
说明如下:
module:模块名,也就是当前的contextPath、当前执行的选择器名
method:方法名,contextPath之后的路径名
rpcType:远程调用类型,目前支持:http、dubbo、springCloud、sofa
httpMethod:http请求方法,目前支持:get和post
sign:请求头携带的签名
timestamp:请求时的时间戳
appKey:请求头携带的appKey
path:请求的真实路径,比如:http/order/findById(http://localhost:9195/http/order/findById?id=9)
contextPath:请求的根路径
realUrl:请求的真实路径
dubboParams:请求的dubbo参数
startDateTime:请求在网关中的开始执行时间
GlobalPlugin处理解析
请求进入GlobalPlugin插件,执行execute
方法。
该方法的作用是构建soulContext上下文
@Override
public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
final ServerHttpRequest request = exchange.getRequest();
final HttpHeaders headers = request.getHeaders();
// 获取请求头“Upgrade”
final String upgrade = headers.getFirst("Upgrade");
// 定义soul上下文对象
SoulContext soulContext;
// 请求头不包含“Upgrade” 或者 不包含“websocket”
if (StringUtils.isBlank(upgrade) || !"websocket".equals(upgrade)) {
// 调用DefaultSoulContextBuilder的 build方法来构建上下文对象
soulContext = builder.build(exchange);
} else {
final MultiValueMap<String, String> queryParams = request.getQueryParams();
soulContext = transformMap(queryParams);
}
exchange.getAttributes().put(Constants.CONTEXT, soulContext);
return chain.execute(exchange);
}
如果请求头不包含“Upgrade” 或者 不包含“websocket”,执行 builder.build(exchange)
方法,即调用DefaultSoulContextBuilder
的 build
方法来构建上下文对象
@Override
public SoulContext build(final ServerWebExchange exchange) {
final ServerHttpRequest request = exchange.getRequest();
// 获取实际的请求路径
String path = request.getURI().getPath();
// 通过缓存,根据实际请求路径获取元数据信息
MetaData metaData = MetaDataCache.getInstance().obtain(path);
// 获取的元数据不为空,并且已启用元数据
if (Objects.nonNull(metaData) && metaData.getEnabled()) {
// 将“metaData” 放到当前exchange的请求属性中
exchange.getAttributes().put(Constants.META_DATA, metaData);
}
return transform(request, metaData);
}
通过build方法,先判断是否有元数据信息,如果有,将“metaData” 放到当前exchange的请求属性中,接着构建soulContext的上下文属性:
private SoulContext transform(final ServerHttpRequest request, final MetaData metaData) {
final String appKey = request.getHeaders().getFirst(Constants.APP_KEY);
final String sign = request.getHeaders().getFirst(Constants.SIGN);
final String timestamp = request.getHeaders().getFirst(Constants.TIMESTAMP);
SoulContext soulContext = new SoulContext();
String path = request.getURI().getPath();
// 设置真实请求路径
soulContext.setPath(path);
// 存在“metaData”数据,进行soulContext上下文赋值处理
if (Objects.nonNull(metaData) && metaData.getEnabled()) {
if (RpcTypeEnum.SPRING_CLOUD.getName().equals(metaData.getRpcType())) {
setSoulContextByHttp(soulContext, path);
soulContext.setRpcType(metaData.getRpcType());
} else if (RpcTypeEnum.DUBBO.getName().equals(metaData.getRpcType())) {
setSoulContextByDubbo(soulContext, metaData);
} else if (RpcTypeEnum.SOFA.getName().equals(metaData.getRpcType())) {
setSoulContextBySofa(soulContext, metaData);
} else if (RpcTypeEnum.TARS.getName().equals(metaData.getRpcType())) {
setSoulContextByTars(soulContext, metaData);
} else {
setSoulContextByHttp(soulContext, path);
soulContext.setRpcType(RpcTypeEnum.HTTP.getName());
}
} else {
// 如果没有meata信息,一般的http请求(普通的springboot微服务应用)
setSoulContextByHttp(soulContext, path);
// 设置rpc类型为:http
soulContext.setRpcType(RpcTypeEnum.HTTP.getName());
}
soulContext.setAppKey(appKey);
soulContext.setSign(sign);
soulContext.setTimestamp(timestamp);
soulContext.setStartDateTime(LocalDateTime.now());
Optional.ofNullable(request.getMethod()).ifPresent(httpMethod -> soulContext.setHttpMethod(httpMethod.name()));
return soulContext;
}
transform
方法就是为soulContext上下文各属性赋值。比较注意的点就是对contextPath和realUrl的操作。
private void setSoulContextByHttp(final SoulContext soulContext, final String path) {
String contextPath = "/";
String[] splitList = StringUtils.split(path, "/");
/**
* 比如请求:http://localhost:9195/http/order/findById?id=9
* path:/http/order/findById
* contextPath:获取真实路径的第一个,为:http
*/
if (splitList.length != 0) {
contextPath = contextPath.concat(splitList[0]);
}
// realUrl:设置contextPath之后的值,为:order/findById
String realUrl = path.substring(contextPath.length());
soulContext.setContextPath(contextPath);
soulContext.setModule(contextPath);
soulContext.setMethod(realUrl);
soulContext.setRealUrl(realUrl);
}
比如请求:http://localhost:9195/http/order/findById?id=9
- path:/http/order/findById
- contextPath:获取真实路径的第一个,为:http
- realUrl:order/findById
赋值完soulContext之后,接着回到GlobalPlugin的execute方法
exchange.getAttributes().put(Constants.CONTEXT, soulContext);
return chain.execute(exchange);
把soulContext放到exchange的请求属性中,完成GlobalPlugin插件的处理,接着执行插件链中的下一个插件。