最后我们来说一下我个人理解的JArslink的设计精髓-----“Action”
首先我们来看一下,SpringModule中的一段代码
private <T> Map<String, T> scanActions(ApplicationContext applicationContext, Class<T> type,
Function<T, String> keyFunction) {
Map<String, T> actions = Maps.newHashMap();
//find Action in module
for (T action : applicationContext.getBeansOfType(type).values()) {
String actionName = keyFunction.apply(action);
if (isBlank(actionName)) {
throw new ModuleRuntimeException("JarsLink scanActions actionName is null");
}
String key = actionName.toUpperCase(Locale.CHINESE);
checkState(!actions.containsKey(key), "Duplicated action %s found by: %s",
type.getSimpleName(), key);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("JarsLink Scan action: {}: bean: {}", key, action);
}
actions.put(key, action);
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("JarsLink Scan actions finish: {}", ToStringBuilder.reflectionToString(actions));
}
return actions;
}
@Override
public Map<String, Action> getActions() {
return actions;
}
@Override
public <R, T> Action<R, T> getAction(String actionName) {
checkNotNull(actionName, "actionName is null");
Action action = actions.get(actionName.toUpperCase());
checkNotNull(action, "find action is null,actionName=" + actionName);
return action;
}
@Override
public <R, T> T doAction(String actionName, R actionRequest) {
checkNotNull(actionName, "actionName is null");
checkNotNull(actionRequest, "actionRequest is null");
return (T) doActionWithinModuleClassLoader(getAction(actionName), actionRequest);
}
我们看到上面的代码大量使用了泛型,我们在实际应用中可以将其替换为我们实际应用中的某个特定的类,该类需要通过spring管理,在上下文中找到指定的该bean,将其和每个模块绑定。
protected <R, T> T doActionWithinModuleClassLoader(Action<R, T> action, R actionRequest) {
checkNotNull(action, "action is null");
checkNotNull(actionRequest, "actionRequest is null");
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
ClassLoader moduleClassLoader = action.getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(moduleClassLoader);
return action.execute(actionRequest);
} catch (Exception e) {
LOGGER.error("调用模块出现异常,action=" + action, e);
throw new ModuleRuntimeException("doActionWithinModuleClassLoader has error,action=" + action, e);
} finally {
Thread.currentThread().setContextClassLoader(classLoader);
}
}
我们可以看到,jarslinjk为我们提供的调用方法思路其实就是根据模块找到对应的Action对象,通过对象获取到当前模块的ClassLoader,调用Action的方法即可,其实我们可以借助这个思路,在实际应用中通过jarslink这种方式调用其实是很不方便的,大体思路就是我们将项目中的所有需要暴漏出的接口类通过一种方式注册为Action即可