java 语言自身具有动态性,通过字节码,类加载实现动态性,我们可以实现自己的字节码动态修改,再让jvm 加载。但是源码进行动态加载呢?
就像php,python 这种及时编译,及时运行。(很方便,省去编译)
下面说说我自己用java实现的一套支持java原生态的动态脚本
实现过程
1、源码编译
2、实现类加载load源码,获取class
3、通过反射,执行返回的class
实现源码如下,有简略的注释,希望大家能看懂。。
ScriptHelper //脚本引擎类
ScriptClassLoader //自定义类加载器
Script //脚本源码类
ScriptHelper
package com.usefullc.crawler.common.script;
import com.usefullc.platform.common.utils.MD5Utils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Created by shengshan.tang on 8/3/2015 at 2:10 PM
* 脚本
*/
public class ScriptHelper {
private final static Logger log = LoggerFactory.getLogger(ScriptHelper.class);
public static Map<String,Object> execute(String scriptContent,Map<String,Object> paramMap){
Map<String,Object> resultMap = new HashMap<String, Object>();
try {
//
String folder = System.getProperty("java.io.tmpdir");
// String fileId = UUID.randomUUID().toString();
String basePath = folder + "crawler";
String sourceFilePath = basePath + File.separator + "source";
if(new File(sourceFilePath).mkdir()){
log.info("init create base source folder");
}
String fileId = "Script_"+MD5Utils.toMD5(scriptContent);
String filePath = sourceFilePath + File.separator + fileId+".java";
log.info("filePath="+filePath);
//operate source java
//获取package
int startIndex = scriptContent.indexOf("package");
int endIndex = scriptContent.indexOf(";",startIndex);
String packageStr = scriptContent.substring(startIndex+7,endIndex).trim();
log.info("packageStr="+packageStr);
scriptContent = scriptContent.replaceAll("Script",fileId); //class name replace
FileUtils.write(new File(filePath),scriptContent,"utf-8");
//compiler
String classFilePath = basePath+File.separator+"classs";
if(new File(classFilePath).mkdir()){
log.info("init create class folder");
}
String libPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
log.info("libPath="+libPath);
libPath = libPath.replace("classes", "lib"); //
libPath = libPath.substring(1);
String classPath = "$CLASS_PATH";
if(SystemUtils.OS_NAME.startsWith("Windows")){
classPath = "%CLASS_PATH%";
}
String cmd = "javac -g -Djava.ext.dirs="+libPath+" -cp "+classPath+" -sourcepath "+sourceFilePath+" -d "+classFilePath+" "+filePath;
log.info("cmd="+cmd);
//exeuce compiler
Process process = Runtime.getRuntime().exec(cmd);
int exitValue = process.waitFor();
log.info("exitValue="+exitValue);
//class loader
ScriptClassLoader classLoader = new ScriptClassLoader(classFilePath);
Class scriptClass = classLoader.findClass(packageStr+"."+fileId);
Object instance = scriptClass.newInstance();
Method method = scriptClass.getDeclaredMethod("execute", Map.class);
method.invoke(instance,paramMap);
}catch(Exception e){
e.printStackTrace();
}
return resultMap;
}
public static void main(String[] args) {
String sourceStr = "package com.usefullc.crawler.common.script;\n" +
"\n" +
"import java.util.Map;\n" +
"import java.util.Set;\n" +
"\n" +
"/**\n" +
" * Created by shengshan.tang on 8/3/2015 at 3:19 PM\n" +
" */\n" +
"public class Script {\n" +
"\n" +
" public void execute(Map<String,Object> paramMap){\n" +
" System.out.println(\"test ok!\");\n" +
" if(paramMap != null && !paramMap.isEmpty()){\n" +
" Set<Map.Entry<String,Object>> entrySet = paramMap.entrySet();\n" +
" for(Map.Entry<String,Object> entry : entrySet){\n" +
" System.out.println(entry.getKey()+\"=\"+entry.getValue());\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n";
Map<String,Object> paramMap = new HashMap<String, Object>();
paramMap.put("name","tangshengshan");
paramMap.put("sex","男");
execute(sourceStr,paramMap);
}
}
//
ScriptClassLoader
package com.usefullc.crawler.common.script;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
/**
* 脚本加载类
* Created by shengshan.tang on 8/3/2015 at 3:52 PM
*/
public class ScriptClassLoader extends ClassLoader {
String classTargetPath;
public ScriptClassLoader(String classTargetPath) {
this.classTargetPath = classTargetPath;
}
@Override
protected Class findClass(String name) throws ClassNotFoundException {
try {
byte bytes[] = getClassBytes(name);
Class thisClass = defineClass(name,bytes,0,bytes.length);
return thisClass;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private byte [] getClassBytes(String className) throws IOException {
//builder class file path
className = className.replace('.', File.separatorChar) + ".class";
String classFilePath = classTargetPath +File.separator+className;
byte [] bytes = FileUtils.readFileToByteArray(new File(classFilePath));
return bytes;
}
}
//
Script
package com.usefullc.crawler.common.script;
import java.util.Map;
import java.util.Set;
/**
* Created by shengshan.tang on 8/3/2015 at 3:19 PM
*/
public class Script {
public void execute(Map<String,Object> paramMap){
System.out.println("test ok!");
if(paramMap != null && !paramMap.isEmpty()){
Set<Map.Entry<String,Object>> entrySet = paramMap.entrySet();
for(Map.Entry<String,Object> entry : entrySet){
System.out.println(entry.getKey()+"="+entry.getValue());
}
}
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
分享到:
相关推荐
本资源为二狗自己编写的快速定义java环境变量的脚本,可以帮助你剩下不少时间,操作前建议备份/etc/profile文件:mv /etc/profile{,.bak} 防止脚本问题覆盖掉文件的内容 资源分为脚本和安装包两部分内容,放置在同一...
为marc数据自定义处理脚本,脚本支持groovy或java语言。 需JAVA 1.6以上,直接运行jar文件或bat文件即可。 联系作者:444057137@qq.com
贝壳在 Java 中使用自定义脚本语言的自定义命令行 shell
cognos自定义java程序登录程序,文件包含sql脚本,jar包,源码文档等。测试在cognos上登录可用,实现cognos自定义用户表权限管理。
1、采用Java语言开发,集成SpringBoot,Redis、Mybatis,SpringEvent、Maven,项目 2、包含前端、后端源码,数据库设计、SQL脚本,抽奖算法如果没有实现思路,这是一个很好的入门案例。
(1)java中获取脚本引擎的方法:获取js引擎:(2)脚本执行时的数据绑定对象:可以自定义一个binding对象:(有两个例子,可以对比一下)脚本执行引擎上下
本文档内容包括: 1.注解详细内容(五个内置注解、...2.java动态性(静态语言、动态语言、反射机制操作(类、属性、注解、构造器)、动态编译、脚本引擎Rhino动态执行JavaScript代码、动态Java字节码操作) --author:
自定义 Graal 指标.
java版微信公众号开发之自定义菜单的创建代码中使用的SQL,创建自定义菜单的代码链接:https://www.blog-china.cn/liuzaiqingshan/home/10/1519376790015
德朗是: 灵活:您可以轻松地嵌入Deelang并为您的用户提供自定义脚本环境。 轻量级:整个Deelang编译器,VM和运行时的重量都小于1MB(包括所需的ANTLR运行时)。 在Android上,使用novm jar将为您的APK添加约300k。 ...
WEB 开发人员的得力工具,只需要在网页中嵌入一个js文件,即使在模式对话框中,也一样方便在线查看网页源码,javascript变量,在页面上执行自定义脚本,即写即运行,不影响被调试页面的外观。 主要功能: 变量 ...
Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...
Java 脚本 API 是一种独立于框架的脚本语言,使用来自于Java代码的脚本引擎 。可以使用Java语言编写定制/可扩展的应用程序并将自定义脚本语言选择留给最终用户 。下面我们来详细了解一下吧
magic-script是一款基于JVM的脚本语言,目前主要是为magic-api项目设计。magic-api,接口快速开发框架,通过Web页面配置,自动映射为HTTP接口;spider-flow,新一代爬虫平台,以图形化方式定义爬虫流程,不写代码...
在UI自动化测试中,相信很多人都喜欢用所谓的PO模式,其中的P,也是page的意思,于是乎,在脚本里,或者在其它的page里,会要new很多的page对象,这样很麻烦,前面我们也讲到了注解的使用,很方便,那么我们可不可以...
完整版Java JSP web开发教程 06_JSP脚本和指令的使用(共22页).ppt 完整版Java JSP web开发教程 07_JSP隐式对象(共32页).ppt 完整版Java JSP web开发教程 08_JavaBean和JSP中(共26页).ppt 完整版Java JSP web...
JSP自定义标签是用户定义的JSP语言元素,可以看成是一种通过标签处理器生成基于XML脚本的方法。自定义标签在功能上和逻辑上都与JavaBean类似,都是一组可重用的组件代码。相较于JavaBean,自定义标签可以使Web开发者...
这是《计算机网络》的...要支持PHP的动态脚本的话,需要自行下载PHP的文件到php目录下,并且更改设置,开启PHP的CGI模式。(请先看下里面的"说明.txt")(温馨提示:下载后评论【需要评选等级】会返回被扣除的积分)
Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...
Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...