相对于客户端,服务器端工作就比较多了。服务器端需要load jar包,利用fliter实现方法级的权限控制
// load service config
logger.info("load service config...");
ServiceConfig sc = loadServiceConfig(gaeaConfigDefaultPath, gaeaConfigPath);
// init class loader
logger.info("-----------------loading global jars------------------");
DynamicClassLoader classLoader = new DynamicClassLoader();
classLoader.addFolder(
rootPath + "service/deploy/" + sc.getString("gaea.service.name") + "/",
rootPath + "service/lib/",
rootPath + "lib"
);
//通过反射调用URLClassLoader的addURL方法
GlobalClassLoader.addSystemClassPathFolder(
rootPath + "service/deploy/" + sc.getString("gaea.service.name") + "/",
rootPath + "service/lib/",
rootPath + "lib"
);
logger.info("-------------------------end-------------------------\n");
if(new File(serviceFolderPath).isDirectory() || serviceName valid) {
// load proxy factory
logger.info("--------------------loading proxys-------------------");
IProxyFactory proxyFactory = ProxyFactoryLoader.loadProxyFactory(classLoader);
Global.getSingleton().setProxyFactory(proxyFactory);
logger.info("-------------------------end-------------------------\n");
// load init beans
logger.info("-----------------loading init beans------------------");
loadInitBeans(classLoader, sc);
logger.info("-------------------------end-------------------------\n");
}
// load global request-filters
logger.info("-----------loading global request filters------------");
List<IFilter> requestFilters = loadFilters(classLoader, sc, "gaea.filter.global.request");
for(IFilter filter : requestFilters) {
Global.getSingleton().addGlobalRequestFilter(filter);
}
logger.info("-------------------------end-------------------------\n");
// load global response-filters
logger.info("-----------loading global response filters-----------");
List<IFilter> responseFilters = loadFilters(classLoader, sc, "gaea.filter.global.response");
for(IFilter filter : responseFilters) {
Global.getSingleton().addGlobalResponseFilter(filter);
}
logger.info("-------------------------end-------------------------\n");
// load connection filters
logger.info("-----------loading connection filters-----------");
List<IFilter> connFilters = loadFilters(classLoader, sc, "gaea.filter.connection");
for(IFilter filter : connFilters) {
Global.getSingleton().addConnectionFilter(filter);
}
logger.info("-------------------------end-------------------------\n");
// load secureKey 当gaea.secure不为true时不启动权限认证
logger.info("------------------load secureKey start---------------------");
if(sc.getString("gaea.secure") != null && "true".equalsIgnoreCase(sc.getString("gaea.secure"))) {
logger.info("gaea.secure:" + sc.getString("gaea.secure"));
loadSecureKey(sc,serviceFolderPath);
}
logger.info("------------------load secureKey end----------------------\n");
// load servers
logger.info("------------------ starting servers -----------------");
loadServers(classLoader, sc);
logger.info("-------------------------end-------------------------\n");
// add current service file to monitor
if(sc.getBoolean("gaea.hotdeploy")) {
logger.info("------------------init file monitor-----------------");
addFileMonitor(rootPath, sc.getString("gaea.service.name"));
logger.info("-------------------------end-------------------------\n");
}
//load proxy factory
//ProxyFactoryLoader.loadProxyFactory
CreateManager cm = new CreateManager();
return cm.careteProxy(Global.getSingleton().getRootPath()
+ "service/deploy/"
+ ("gaea.service.name"),
classLoader);
// CreateManager.createProxy
//ContractInfo
if (file != null && file.exists()) {
//如果存在Serviceframe.xml
serviceContract = ContractConfig.loadContractInfo(configPath, classLoader);
} else {
//只扫描deploy/{serviceName}目录下的jar包
serviceContract = ScanClass.getContractInfo(serviceRootPath + "/", classLoader);
}
ServerContract是SessionBean的列表,SessionBean包括接口名,接口->实例Map,类信息。在Serviceframe.xml中可配置.
如果存在Serviceframe.xml,则扫描Serviceframe.xml,否则直接扫描jar包。
Serviceframe.xml的格式为:
<interface>
<class></class>
<lookup></lookup>
</interface>
// ScanClass.getContractInfo
//扫描注解,分别解析contract(接口),behavior(实现)
ServiceBehaviorbehavior = cls.getAnnotation(ServiceBehavior.class);
ServiceContract contract= cls.getAnnotation(ServiceContract.class);
if(behavior==null && contract == null) {
continue;
}
if(contract !=null) {
ClassInfo ci = contract(cls);
if(ci !=null) {
contractClassInfos.add(ci);
}
} elseif(behavior!= null) {
ClassInfo ci = behavior(cls);
if(ci !=null) {
behaviorClassInfos.add(ci);
}
}
//ScanClass.Contract()
//获取该类所有接口
List<Class<?>>interfaceList = getInterfaces(cls);
List<ClassInfo.MethodInfo>methodInfos = newArrayList<ClassInfo.MethodInfo>();
for(Class<?>interfaceCls : interfaceList) {
//接口所有方法
Method[]methods = interfaceCls.getDeclaredMethods();
if(contractAnn!=null && contractAnn.defaultAll()){
for(Methodm : methods) {
if(Modifier.isPublic(m.getModifiers())|| Modifier.isProtected(m.getModifiers())) {
ClassInfo.MethodInfo mi =newClassInfo.MethodInfo();
mi.setMethod(m);
methodInfos.add(mi);
}
}
}else {
//没有@ServiceContract注解则默认扫Public并OperationContract注解了的方法
for(Methodm : methods) {
if(Modifier.isPublic(m.getModifiers())|| Modifier.isProtected(m.getModifiers())) {
OperationContract oc =m.getAnnotation(OperationContract.class);
if(oc !=null) {
ClassInfo.MethodInfo mi =newClassInfo.MethodInfo();
mi.setMethod(m);
methodInfos.add(mi);
}
}
}
}
}
//ScanClass.behavior()
//扫描Method,如果发现HttpPathParameter注解,则加载RequestMapping。
//构造ContractInfo
//根据以上两步结果,构造ContractInfo
contractInfo =createContractInfo(contractClassInfos,behaviorClassInfos);
//构造过程
ContractInfocontractInfo = new ContractInfo();
List<SessionBean>sessionBeanList = newArrayList<SessionBean>();
for(ClassInfoc : contracts) {
SessionBeanbean = new SessionBean();
bean.setInterfaceClass(c);
bean.setInterfaceName(c.getCls().getName());
Map<String,String> implMap = newHashMap<String, String>();
//扫描和接口匹配的实现
for(ClassInfob : behaviors) {
Class<?>[]interfaceAry = b.getCls().getInterfaces();
for(Class<?>item : interfaceAry) {
if(item ==c.getCls()) {
implMap.put(b.getLookUP(),b.getCls().getName());
break;
}
}
}
bean.setInstanceMap(implMap);
sessionBeanList.add(bean);
}
contractInfo.setSessionBeanList(sessionBeanList);
return contractInfo;
//创建ProxyClass
List<ClassFile> localProxyList = new ProxyClassCreater().createProxy(classLoader, serviceContract, time);
//ProxyClassCreater.createProxy()
String proxyClassName = lookup + "ProxyStub" + time;
CtClass ctProxyClass = pool.makeClass(proxyClassName, null);
ctProxyClass.addInterface(localProxy); // IProxyStub接口
CtField proxyField = CtField.make( //构造实例
"private static " +sessionBean.getInterfaceName() +" serviceProxy = new " +implClassName +"();", ctProxyClass);
ctProxyClass.addField(proxyField);
//创建 method
for(Method m : uniqueMethodList) {
logger.debug("create method:" + m.getName());
String methodStr = createMethods(proxyClassName, m.getName(), allMethodList, uniqueNameList);
CtMethod methodItem = CtMethod.make(methodStr, ctProxyClass);
ctProxyClass.addMethod(methodItem);
}
//创建invoke方法
String invokeMethod = createInvoke(proxyClassName, uniqueNameList);
logger.debug("create invoke method:" + invokeMethod);
CtMethod invoke = CtMethod.make(invokeMethod, ctProxyClass);
ctProxyClass.addMethod(invoke);
clsList.add(new ClassFile(proxyClassName, ctProxyClass.toBytecode()));
}
//Invoke方法体,使用到了GaeaResponse和GaeaContext
private String createInvoke(String className, List<String> uniqueNameList) {
StringBuilder sb = new StringBuilder();
sb.append("public " + Constant.GAEARESPONSE_CLASS_NAME + " invoke(" + Constant.GAEACONTEXT_CLASS_NAME + " context) throws " + Constant.SERVICEFRAMEEXCEPTION_CLASS_NAME + " {");
sb.append("String methodName = ((" + Constant.REQUEST_PROTOCOL_CLASS_NAME + ")context.getGaeaRequest().getProtocol().getSdpEntity()).getMethodName();");
for (String methodName : uniqueNameList) {
sb.append("if(methodName.equalsIgnoreCase(\"");
sb.append(methodName);
sb.append("\")){return ");
sb.append(methodName);
sb.append("(context);}");
}
sb.append("throw new " + Constant.SERVICEFRAMEEXCEPTION_CLASS_NAME + "(\"method:" + className + ".invoke--msg:not found method (\"+methodName+\")\", context.getChannel().getRemoteIP(), context.getChannel().getLocalIP(), context.getGaeaRequest().getProtocol().getSdpEntity(), " + Constant.ERRORSTATE_CLASS_NAME + ".NotFoundMethodException, null);");
sb.append("}");
return sb.toString();
}
ClassFile cfProxyFactory = new ProxyFactoryCreater().createProxy(classLoader, serviceContract, time);
IProxyFactory pfInstance = (IProxyFactory)constructor.newInstance(localProxyAry);
//constructor为ProxyFactory实例,里面初始化所有实例
//gaea.init的init方法
// load init beans
loadInitBeans(classLoader, sc);
//loadSecureKey最终将配置文件中//secure信息添加到Global.secureMap
loadSecureKey(sc,serviceFolderPath);
// load servers
loadServers(classLoader, sc);
//建立gaea.servers[].implement实例并调用start
主要工作总结如下:
解析gaea配置文件gaea_config.xml
添加jar包到系统Classloader
扫描deploy/{serviceName}下的jar包,根据@ServiceContract等注解建立实现类(SessionBean)和该实现类对应接口的映射关系。
创建SessionBean对应的代理ProxyStub,该代理类负责将调用转交给实现类,并在接口上对参数做一层包装。分别使用GaeaResponse和GaeaContext为返回、参数类型。
创建Proxy工厂类,包含了SessionBean实例。
加载Filter
加载SecureKey配置
调用配置文件gaea.init的方法
加载Server
Proxy工厂类其实是以后请求处理的入口,客户端请求经过包装后发送到服务器端,服务器端解析消息,Proxy工厂根据消息调用对应SessionBean的某个方法。