動態發佈接口java
HTTP接口分爲REST和SOAP2種方式,文中都涉及到,包含從動態生成文件到編譯class再到裝載到spring容器和ws.Endpoint中。web
REST風格
redis
方案:spring
1.提供java文件模板app
2.讀取文件內容ide
3.查庫修改生成java文件工具
4.經過JDK中的javax.tools.JavaCompiler動態編譯成class
編碼
5.經過繼承java.net.URLClassLoader動態加載class文件到內存spa
6.經過獲取spring的ApplicationContext手動把mapping註冊到RequestMappingHandlerMapping中完成動態發佈.net
過程:
1.模板文件根據業務自行配置(涉及公司機密,忽略)
2.讀取文件內容,生成java文件,編譯class,加載class,發佈接口
//動態建立接口 @Override public Boolean createGenerate(String serviceName,Long interfaceId,String structrue) { try { //首字母大寫 serviceName = StringUtils.firstCharUpper(serviceName); //目錄路徑 Path directoryPath = Paths.get(outDirectory); // 若是目錄不存在 if (!Files.exists(directoryPath)) { //建立目錄 Files.createDirectories(directoryPath); } String controllerJava = serviceName + "Controller.java"; String autoJavaFile = outDirectory + controllerJava; //文件路徑 Path filePath = Paths.get(autoJavaFile); if (!Files.exists(filePath)) { //建立文件 Files.createFile(filePath); } else { logger.error("動態建立接口錯誤,文件已存在:"+autoJavaFile); return false; } // 讀取模板文件流 String javaFile = directory + "RestTemplateController.java"; String content = FileUtils.readFile(javaFile); //替換文件 content = replaceJava(content, serviceName, interfaceId,structrue); //寫入文件 Files.write(filePath, content.getBytes(charsetName)); String fullName = packageName + serviceName + "Controller"; //動態編譯class JavaStringCompiler compiler = new JavaStringCompiler(); Map<String, byte[]> results = compiler.compile(controllerJava, content); //加載class Class<?> clzMul = compiler.loadClass(fullName, results); //獲取spring的applicationContext ApplicationContext applicationContext = SpringContextHelper.getApplicationContext(); //註冊接口到註冊中心 MappingRegulator.controlCenter(clzMul, applicationContext, create); } catch (Exception e) { logger.error("動態建立接口錯誤",e); return false; } return true; } /** * controlCenter(運行時RequestMappingHandlerMapping中添加、刪除、修改Mapping接口) * @param Class 但願加載的類Class * @param ApplicationContext spring上下文 * @param type 1新增 2修改 3刪除 * @throws Exception * @throws IllegalAccessException * @Exception 異常對象 * @since CodingExample Ver(編碼範例查看) 1.1 * @author jiaxiaoxian */ public static void controlCenter(Class<?> controllerClass,ApplicationContext Context,Integer type) throws IllegalAccessException, Exception{ //獲取RequestMappingHandlerMapping RequestMappingHandlerMapping requestMappingHandlerMapping=(RequestMappingHandlerMapping) Context.getBean("requestMappingHandlerMapping"); Method getMappingForMethod =ReflectionUtils.findMethod(RequestMappingHandlerMapping.class, "getMappingForMethod",Method.class,Class.class); //設置私有屬性爲可見 getMappingForMethod.setAccessible(true); //獲取類中的方法 Method[] method_arr = controllerClass.getMethods(); for (Method method : method_arr) { //判斷方法上是否有註解RequestMapping if (method.getAnnotation(RequestMapping.class) != null) { //獲取到類的RequestMappingInfo RequestMappingInfo mappingInfo = (RequestMappingInfo) getMappingForMethod.invoke(requestMappingHandlerMapping, method,controllerClass); if(type == 1){ //註冊 registerMapping(requestMappingHandlerMapping, mappingInfo, controllerClass, method); }else if(type == 2){ //取消註冊 unRegisterMapping(requestMappingHandlerMapping, mappingInfo); registerMapping(requestMappingHandlerMapping, mappingInfo, controllerClass, method); }else if(type == 3){ unRegisterMapping(requestMappingHandlerMapping, mappingInfo); } } } } /** * * registerMapping(註冊mapping到spring容器中) * @param requestMappingHandlerMapping * @Exception 異常對象 * @since CodingExample Ver(編碼範例查看) 1.1 * @author jiaxiaoxian */ public static void registerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping,RequestMappingInfo mappingInfo, Class<?> controllerClass, Method method) throws Exception, IllegalAccessException{ requestMappingHandlerMapping.registerMapping(mappingInfo, controllerClass.newInstance(),method); } /** * * unRegisterMapping(spring容器中刪除mapping) * @param requestMappingHandlerMapping * @Exception 異常對象 * @since CodingExample Ver(編碼範例查看) 1.1 * @author jiaxiaoxian */ public static void unRegisterMapping(RequestMappingHandlerMapping requestMappingHandlerMapping,RequestMappingInfo mappingInfo) throws Exception, IllegalAccessException{ requestMappingHandlerMapping.unregisterMapping(mappingInfo); }
結果:
能夠正常發佈spring接口,動態生成文件注入mapping到spring接口中。
SOAP風格
方案:
1.提供java文件模板
2.讀取文件內容
3.查庫修改生成java文件
4.經過JDK中的javax.tools.JavaCompiler動態編譯成class
5.經過繼承java.net.URLClassLoader動態加載class文件到內存
6.經過javax.xml.ws.Endpoint的publish動態發佈接口
過程:
1.模板文件根據業務自行配置(涉及公司機密,忽略)
2.讀取文件內容,生成java文件,編譯class,加載class,經過Endpoint發佈接口
@Override public Boolean createGenerate(String serviceName, Long interfaceId, String structrue) { try { serviceName = StringUtils.firstCharUpper(serviceName); Path directoryPath = Paths.get(outDirectory); // 若是文件不存在 if (!Files.exists(directoryPath)) { Files.createDirectories(directoryPath); } String controllerJava = serviceName + "Controller.java"; String autoJavaFile = outDirectory + controllerJava; Path filePath = Paths.get(autoJavaFile); if (!Files.exists(filePath)) { Files.createFile(filePath); } else { logger.error("動態建立接口錯誤ws,文件已存在:" + autoJavaFile); return false; } String wsJavaFile = directory + "JwsTemplateController.java"; String content = FileUtils.readFile(wsJavaFile); content = replaceJava(content, serviceName, interfaceId, structrue); Files.write(filePath, content.getBytes(charsetName)); String fullName = packageName + serviceName + "Controller"; JavaStringCompiler compiler = new JavaStringCompiler(); Map<String, byte[]> results = compiler.compile(controllerJava, content); Class<?> clzMul = compiler.loadClass(fullName, results); publish(clzMul, serviceName); } catch (Exception e) { logger.error("動態建立接口錯誤ws", e); return false; } return true; } //動態發佈接口 private void publish(Class<?> clzMul, String serviceName) throws Exception { serviceName = firstCharLower(serviceName); Endpoint endpoint = Endpoint.create(clzMul.newInstance()); endpoint.publish(wsDomain + serviceName); //redisUtil.set(serviceName, endpoint); endpointMap.put(serviceName, endpoint); }
結果:
能夠正常發佈SOAP接口,動態生成文件發佈SOAP接口。
後面附件會上傳動態生成須要的工具類,須要的小夥伴能夠下載,記得好評!
author:賈小仙
time:2018/9/5