动态发布接口

动态发布接口-贾小仙-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接口。

原文地址:https://www.cnblogs.com/rsapaper/p/10006310.html