本地服务是部署在同一个jvm中相同的模块或者不同的模块之间的服务调用。
因各模块有自己的运行空间,拥有独立的ClassLoader,因此模块间的服务调用也会存在差异。
模块内的服务调用,类似Spring,获取Bean的实例,并调用相关方法:
@Service("AuthService")
public class AuthService extends AbstractService{
public Data auth(@Param(value="principal",required=true)Principal principal,
@Param(value="url",required=true)String url) throws Exception {
User user = (User)principal;
MenuService ms = module.getService(MenuService.class);
Data menu = ms.findByUrl(url);
long perm_id = menu.getLong("perm_id", 0);
if(perm_id == 0) return new Data("authResult", true); //not protected url
List<String> perm_ids = user.getData().get("perm_ids");
for(String pid: perm_ids) {
if(Long.parseLong(pid) == perm_id)
return new Data("authResult", true);
}
return new Data("authResult", false);
}
}
这种使用的优势:
1、MenuService的引用非常清晰,如果后续发生重构等,也会跟着完成重构。
2、MenuService的方法findByUrl(url)显式被调用,更易于阅读;
缺点,只能在当前模块中调用,否则会出现ClassNotFoundException的。
模块间的服务调用,无论是模块内部或者模块间都可以采用这种方式:
public abstract class ServiceHelper {
private static Map<String, Map<String, Map<String, Object>>> cache = Utils.newHashMap();
public static Data invoke(String moduleId, String serviceId, Data request) throws Exception {
return Application.getInstance().getModules().getModule(moduleId).invoke(serviceId, request);
}
}
调用时:ServiceHelper.invoke("pas","AuthService:auth",new Data("principal",principalInstance,"url","http://localhost:8080/pas/index.shtml"));
参数pas:是服务所在的模块
参数AuthService:auth:服务ID和调用的服务方法,中间使用英文冒号分开
参数Data:auth方法需要的参数
关注红色的principal和url,这个跟参数的Param注解声明的必须是一致的,参考上面auth方法的声明。
优势:太方便了
不足:在可读性上存在一些缺陷,但是考虑到你正在用别人的service,这样已经很方便了,不是吗。
实现,LocalModule中的invoke方法:
public Data invoke(String serviceId, Data request) {
LocalModule currentModule = ThreadContext.getContext().getModule();
ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader();
String sid = ThreadContext.getContext().getServiceId();
Data req = ThreadContext.getContext().getRequest();
Principal p = ThreadContext.getContext().getPrincipal();
Data response = null;
try {
Thread.currentThread().setContextClassLoader(this.getClassLoader());
ThreadContext.getContext().reset(this, serviceId, request, p);
response = ModuleServiceInvoker.invoke(this, request, serviceId);
return response;
} finally {
Thread.currentThread().setContextClassLoader(threadClassLoader);
ThreadContext.getContext().reset(currentModule, sid, req, p);
}
}
注意红色部分ClassLoader切换,因此可以在不同的模块间调用服务。
框架源码:https://github.com/hifong/flying
博客空间:http://www.cnblogs.com/hifong/
Demo应用:https://github.com/hifong/pas
技术QQ群:455852142