动态发布接口

    HTTP接口分为RESTSOAP2种方式,文中都涉及到,包含从动态生成文件到编译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
 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
 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