手机购彩

让梦想从这里开始

因为有了梦想,我们才能拥有奋斗的目标,而这些目标凝结成希望的萌芽,在汗水与泪水浇灌下,绽放成功之花。

动态编译生成Java类

发布日期:2022-05-21 22:22    点击次数:205

动态创建bean,前面一篇介绍了通过cglib来创建的方式,虽然实现了动态创建javabean,但是有一个问题,javabean中的fieldname和我们预期的不太一致

接下来我们介绍一种直接通过拼接java代码,然后再将其编译成class并加载,从而实现动态类的创建

1.java代码动态编译创建

接下来我们主要借助jdk自带的JavaCompiler来实现java源码的编译,生成class,然后交由ClassLoader来加载类

如果我们现在有个java文件,希望在项目运行时,动态编译并加载类,一般的操作流程如下

JavaCompilercompiler=ToolProvider.getSystemJavaCompiler;intcompilationResult=compiler.run(null,null,null,'/path/Test.java');复制代码

相比于存在的java文件,我们更多的场景则是针对String的java源码,基于它来创建java类

测试则需要针对上面的逻辑进行扩展;如果不想关心细节,直接使用开源的三方包来实现

com.itranswarpcompiler1.0复制代码

同样我们来实现一个根据Map,来生成javabean的方式

基于javacode来生成源码

/***编译java代码,并生成对象**@parampackageName包名*@paramclassName类名*@paramjavaCode源码*@return*@throwsException*/publicObjectcreateBean(StringpackageName,StringclassName,StringjavaCode)throwsException{JavaStringCompilercompiler=newJavaStringCompiler;Mapresult=compiler.compile(className+".java","package"+packageName+";\n"+javaCode);Classclz=compiler.loadClass(packageName+"."+className,result);returnclz.newInstance;}复制代码

接下来我们需要实现的是根据map来生成对应的javacode

privateStringgenCode(StringclzName,Mapmap){StringBuilderbuilder=newStringBuilder("publicclass").append(clzName).append("{\n");for(Map.Entryobj:map.entrySet){StringfieldType;if(obj.getValueinstanceofList){fieldType="java.util.List";}elseif(obj.getValueinstanceofSet){fieldType="java.util.Set";}elseif(obj.getValueinstanceofMap){fieldType="java.util.Map";}else{fieldType=obj.getValue.getClass.getName.replace("$",".");}builder.append("\tpublic").append(fieldType).append("").append(obj.getKey).append(";\n");}builder.append("}");returnbuilder.toString;}复制代码

注意上面的实现,现在只是最基础的实现,需要注意,如果value的类型,是一个内部类,就可能有坑(比如上面针对容器类进行了特殊处理)

最后测试一下

@TestpublicvoidtestGenMapBeanthrowsException{Mapmap=newHashMap;map.put("hello","world");map.put("key",12);map.put("list",Arrays.asList(1,2,3));StringpackageName="com.git.hui.dynamic";StringclzName="MBean1";Stringcode=genCode(clzName,map);Objectbean=createBean(packageName,clzName,code);//初始化bean的成员for(Map.Entryentry:map.entrySet){Fieldfield=bean.getClass.getField(entry.getKey);field.set(bean,entry.getValue);}System.out.println("----------------javacode---------------\n"+code+"\n------------------");System.out.println(JSON.toJSONString(bean));}复制代码

上面给出了一个根据Map生成bean对象,并初始化成员值的实例

输出如下

----------------javacode---------------publicclassMBean1{publicjava.lang.Stringhello;publicjava.util.Listlist;publicjava.lang.Integerkey;}------------------{"hello":"world","key":12,"list":[1,2,3]}复制代码

输出和我们预期一致,直接通过组装java代码,然后来生成对象

那么这种方式应用场景在什么地方呢?

比如我之前做过一个动态脚本执行的框架,可以在控制台上写java代码,写完之后直接交给框架来运行;当然这种选择groovy来做脚本可能更优雅一些






Powered by 手机购彩 @2013-2022 RSS地图 HTML地图