zoukankan      html  css  js  c++  java
  • 动态发布接口

    动态发布接口-贾小仙-51CTO博客 http://blog.51cto.com/hackerxian/2170593

    2018-09-05 12:39:43

    动态发布接口

        HTTP接口分为REST和SOAP2种方式,文中都涉及到,包含从动态生成文件到编译class再到装载到spring容器和ws.Endpoint中。

        

        REST风格

            方案:

                1.提供java文件模板

                2.读取文件内容

                3.查库修改生成java文件

                4.通过JDK中的javax.tools.JavaCompiler动态编译成class

                5.通过继承java.net.URLClassLoader动态加载class文件到内存

                6.通过获取spring的ApplicationContext手动把mapping注册到RequestMappingHandlerMapping中完成动态发布

            过程:

                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接口。

  • 相关阅读:
    对网页图片的增删改管理
    还没搞完的排序(后期更新)
    web实现图片动态
    C++11 笔记
    如何解决刷新系统桌面响应速度很慢的问题
    CGrowableArray解析 _ DXUT容器
    测试...外部指针访问private
    CustomUI Direct3D9_Sample
    缺少.lib文件导致的Link2019 解决方案汇总
    在DirectX9中使用DXUT定制按钮来控制模型旋转的问题
  • 原文地址:https://www.cnblogs.com/rsapaper/p/10006310.html
Copyright © 2011-2022 走看看