springboot动态发布接口 动态编译class

           1.通过velocity模板,生成Java模板

            2.通过命令行Process process = Runtime.getRuntime().exec(commod);动态编译成class

            3.通过class.forName("包类名字")加载字节码成为class对象

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

巨坑:https://github.com/michaelliao/compiler属于2016年不在维护的项目,issue上面spring boot中是会报错的,因此放弃了通过内存创建文件的方式,如果新生成的Java类需要依赖非jdk以外的第三方组件是会编译报错的,这篇文章在spring boot下是不会编译成功的,这篇文章写的过于复杂,其实不需要自定义写classload

第一步:生成java文件,其中content是通过模板生成的Java类内容,这里省去了模板的创建

 String content = "package com.test;public class TestDemo{private String studentId;public String getStudentId()
 {return this.studentId;}public void setStudentId(String studentId){this.studentId = studentId;}}";
        String fileName ="D/...TestDemo.java";
        File file = new File(fileName);
        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write(content);
        fileWriter.flush();
        fileWriter.close();
		

第二步;编译 class文件

  /**
     * 编译java类
     * 使用Runtime执行javac命令
     * @param packageAndClass类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @throws java.io.IOException
     */
    public static void javac(String packageAndClass,String jarAbsolutePath) throws IOException {
    
      
        Process process = Runtime.getRuntime().exec("javac -cp"+ jarAbsolutePath+ " " + packageAndClass);
        try {
            InputStream errorStream = process.getErrorStream();
            InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String line = null;
            while ((line=bufferedReader.readLine()) != null){
                System.out.println(line);
            }
//如果大于0,表明 编译成功,可以手工CMD编译
            int exitVal = process.waitFor();
            System.out.println("Process exitValue: " + exitVal);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

第三步:从class文件得到类对象及字节码数组

//classAbsolutePath为新生成的Java类对应的class文件路径,采用命令行编译后,class文件会跟Java文件放在同一目录下
        byte[] bytes = Files.readAllBytes(Paths.get(classAbsolutePath));
//通过class.forName("包类名")可以获取到对象

 

第四步:注入spring中 

/**
	* 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);
	}

 

你可能感兴趣的:(springboot动态发布接口 动态编译class)