本地服务调用

本地服务是部署在同一个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

posted @ 2016-04-27 22:18  hifong  阅读(513)  评论(0编辑  收藏  举报