相对于客户端,服务器端工作就比较多了。服务器端需要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,否则直接扫描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 { //没有注解则默认扫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(); }
//创建ProxyFactory
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的某个方法。