PowerJob的DesignateServer工作流程源碼解讀
序
本文主要研究一下PowerJob的DesignateServer
DesignateServer
tech/powerjob/server/remote/server/redirector/DesignateServer.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DesignateServer {
/**
* 轉(zhuǎn)發(fā)請(qǐng)求需要 AppInfo 下的 currentServer 信息,因此必須要有 appId 作為入?yún)ⅲ撟侄沃付?appId 字段的參數(shù)名稱,默認(rèn)為 appId
* @return appId 參數(shù)名稱
*/
String appIdParameterName() default "appId";
}DesignateServer注解定義了appIdParameterName屬性,默認(rèn)是appId
DesignateServerAspect
tech/powerjob/server/remote/server/redirector/DesignateServerAspect.java
@Slf4j
@Aspect
@Component
@Order(0)
@RequiredArgsConstructor
public class DesignateServerAspect {
private final TransportService transportService;
private final AppInfoRepository appInfoRepository;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@Around(value = "@annotation(designateServer))")
public Object execute(ProceedingJoinPoint point, DesignateServer designateServer) throws Throwable {
// 參數(shù)
Object[] args = point.getArgs();
// 方法名
String methodName = point.getSignature().getName();
// 類名
String className = point.getSignature().getDeclaringTypeName();
Signature signature = point.getSignature();
// 方法簽名
MethodSignature methodSignature = (MethodSignature) signature;
String[] parameterNames = methodSignature.getParameterNames();
String[] parameterTypes = Arrays.stream(methodSignature.getParameterTypes()).map(Class::getName).toArray(String[]::new);
Long appId = null;
for (int i = 0; i < parameterNames.length; i++) {
if (StringUtils.equals(parameterNames[i], designateServer.appIdParameterName())) {
appId = Long.parseLong(String.valueOf(args[i]));
break;
}
}
if (appId == null) {
throw new PowerJobException("can't find appId in params for:" + signature);
}
// 獲取執(zhí)行機(jī)器
AppInfoDO appInfo = appInfoRepository.findById(appId).orElseThrow(() -> new PowerJobException("can't find app info"));
String targetServer = appInfo.getCurrentServer();
// 目標(biāo)IP為空,本地執(zhí)行
if (StringUtils.isEmpty(targetServer)) {
return point.proceed();
}
// 目標(biāo)IP與本地符合則本地執(zhí)行
if (Objects.equals(targetServer, transportService.defaultProtocol().getAddress())) {
return point.proceed();
}
log.info("[DesignateServerAspect] the method[{}] should execute in server[{}], so this request will be redirect to remote server!", signature.toShortString(), targetServer);
// 轉(zhuǎn)發(fā)請(qǐng)求,遠(yuǎn)程執(zhí)行后返回結(jié)果
RemoteProcessReq remoteProcessReq = new RemoteProcessReq()
.setClassName(className)
.setMethodName(methodName)
.setParameterTypes(parameterTypes)
.setArgs(args);
final URL friendUrl = ServerURLFactory.process2Friend(targetServer);
CompletionStage<AskResponse> askCS = transportService.ask(Protocol.HTTP.name(), friendUrl, remoteProcessReq, AskResponse.class);
AskResponse askResponse = askCS.toCompletableFuture().get(RemoteConstant.DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (!askResponse.isSuccess()) {
throw new PowerJobException("remote process failed: " + askResponse.getMessage());
}
// 考慮范型情況
Method method = methodSignature.getMethod();
JavaType returnType = getMethodReturnJavaType(method);
return OBJECT_MAPPER.readValue(askResponse.getData(), returnType);
}
//......
}DesignateServerAspect攔截了@DesignateServer注解,它先解析方法參數(shù)名,取出參數(shù)名與@DesignateServer的appIdParameterName一致的參數(shù)值,再通過(guò)appInfoRepository.findById找到AppInfoDO,獲取appInfo.getCurrentServer();若currentServer就是本機(jī)則執(zhí)行point.proceed(),否則構(gòu)建RemoteProcessReq,通過(guò)transportService.ask轉(zhuǎn)發(fā)請(qǐng)求
示例
tech/powerjob/server/core/instance/InstanceLogService.java
/**
* 獲取日志的下載鏈接
* @param appId AOP 專用
* @param instanceId 任務(wù)實(shí)例 ID
* @return 下載鏈接
*/
@DesignateServer
public String fetchDownloadUrl(Long appId, Long instanceId) {
String url = "http://" + NetUtils.getLocalHost() + ":" + port + "/instance/downloadLog?instanceId=" + instanceId;
log.info("[InstanceLog-{}] downloadURL for appId[{}]: {}", instanceId, appId, url);
return url;
}fetchDownloadUrl指定了@DesignateServer注解,會(huì)根據(jù)appId的值限定在指定server執(zhí)行
小結(jié)
PowerJob的DesignateServer注解定義了appIdParameterName屬性,默認(rèn)是appId;DesignateServerAspect攔截了@DesignateServer注解,它判斷currentServer就是本機(jī)則執(zhí)行point.proceed(),否則構(gòu)建RemoteProcessReq,通過(guò)transportService.ask轉(zhuǎn)發(fā)請(qǐng)求到指定server執(zhí)行。
以上就是PowerJob的DesignateServer工作流程源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于PowerJob DesignateServer的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java中的延遲隊(duì)列DelayQueue詳細(xì)解析
這篇文章主要介紹了Java中的延遲隊(duì)列DelayQueue詳細(xì)解析,JDK自身支持延遲隊(duì)列的數(shù)據(jù)結(jié)構(gòu),其實(shí)類:java.util.concurrent.DelayQueue,<BR>我們通過(guò)閱讀源碼的方式理解該延遲隊(duì)列類的實(shí)現(xiàn)過(guò)程,需要的朋友可以參考下2023-12-12
Spring Security驗(yàn)證流程剖析及自定義驗(yàn)證方法
Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問(wèn)控制解決方案的安全框架。這篇文章主要介紹了Spring Security驗(yàn)證流程剖析及自定義驗(yàn)證方法,需要的朋友可以參考下2018-03-03
String類型傳遞是值傳遞,char[]類型傳遞是引用傳遞的實(shí)現(xiàn)
下面小編就為大家?guī)?lái)一篇String類型傳遞是值傳遞,char[]類型傳遞是引用傳遞的實(shí)現(xiàn)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看不2016-09-09
SpringBoot中實(shí)現(xiàn)GraphQL訂閱的示例代碼
本文主要介紹了SpringBoot中實(shí)現(xiàn)GraphQL訂閱的示例代碼,GraphQL訂閱能夠?qū)崿F(xiàn)實(shí)時(shí)數(shù)據(jù)推送,為開(kāi)發(fā)者提供了一種高效、靈活的API設(shè)計(jì)和數(shù)據(jù)交互方式2026-02-02
Java方法重載實(shí)現(xiàn)原理及代碼實(shí)例
這篇文章主要介紹了Java方法重載實(shí)現(xiàn)原理及代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
利用feign調(diào)用返回object類型轉(zhuǎn)換成實(shí)體
這篇文章主要介紹了利用feign調(diào)用返回object類型轉(zhuǎn)換成實(shí)體,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
Java文件操作與IO流詳解(File類+字節(jié)流+字符流)
文章主要介紹了文件、路徑和文件類型(文本文件和二進(jìn)制文件)的概念,并詳細(xì)介紹了Java中File類和FileInputStream、FileOutputStream、FileReader、FileWriter等幾個(gè)流類的操作方式,需要的朋友可以參考下2026-04-04

