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} 防止脚本问题覆盖掉文件的内容 资源分为脚本和安装包两部分内容,放置在同一...
与传统的脚本语言(如JavaScript)相比,Java自定义标签能够更好地利用Java的强大功能,提高代码的可维护性和可扩展性。 #### 2. Java自定义标签的优势 - **封装性**:可以将复杂的业务逻辑封装到一个简单的标签中...
这种方式尤其适用于那些需要频繁调整数据库结构的项目,因为它允许开发者快速地修改Java类而无需手动修改数据库脚本。同时,由于自定义注解的灵活性,我们可以根据实际需求扩展其功能,例如添加列约束、索引或触发器...
该项目是一款基于Java语言开发的自定义脚本语言解释器设计源码,总计包含85个文件,其中包含75个Java源文件,以及2个Git忽略文件、2个XML配置文件、2个Gradle文件、1个Markdown文件、1个jar文件和1个属性文件。...
9. **自定义逻辑扩展**:高级的自定义表单系统还允许用户添加自定义脚本或逻辑,比如通过Groovy或JavaScript来扩展表单行为,实现更复杂的业务规则。 10. **版本控制**:表单的设计和配置通常会经历多个版本,因此...
《为marc数据自定义处理脚本--PxMarcScript_0.1》是针对图书馆编目领域的一个实用工具,它允许用户使用Groovy或Java语言编写自定义脚本来处理MARC数据。MARC(Machine-readable Cataloging)是图书馆界广泛采用的一...
总结,"java自定义服务器检验工具类"是一个重要的开发实践,它通过提供预定义的验证函数,帮助开发者高效地处理服务器端的数据验证和安全问题。结合Maven Webapp项目,我们可以构建出一套完整的、可维护的服务器端...
Java启动脚本生成工具是一款非常实用的开发辅助软件,它能帮助Java开发者快速生成适用于Windows和Linux操作系统的启动脚本,极大地提高了工作效率,避免了手动编写脚本的繁琐过程。这款工具的核心功能在于自动化处理...
例如,你可以编写一个Java应用,其中包含一个JavaScript引擎,用于执行用户输入的脚本,实现自定义的数据处理或者用户界面交互。动态脚本也可以用来扩展Java类的功能,提供一种轻量级的插件系统,无需重新编译整个...
同时,它也支持类加载,意味着你可以动态地引入自定义的Java类并立即使用它们。BeanShell还具有对Java反射的支持,可以方便地操作对象、方法和字段,这在处理复杂的程序逻辑时非常有帮助。 描述中提到的博客链接...
在Java编程中,生成验证码(CAPTCHA)是一项常见的任务,常用于网站的身份验证,防止恶意自动脚本或机器人进行操作。验证码通常是一串随机字符,用户需要正确输入才能完成特定的交互。这篇博客"java 自定义信息 生成...
2. Jar包:这是编译后的Java代码,可能包含了自定义的身份验证服务类,这些类会与Cognos的认证框架集成,用于处理用户的登录请求,验证用户身份,并从自定义数据源获取用户的角色和权限。 3. 源码文档:这部分内容...
标题“Java写游戏脚本钩子问题.docx”暗示了一个关于使用Java进行游戏脚本开发时遇到的特定问题,...开发者需要掌握如何利用Java的面向对象特性、多线程、动态性和分布性来克服挑战,实现高效、安全的游戏脚本编写。
读者可以在所提供的博客链接中找到更多关于这个自定义脚本的详细信息。在该博客中,作者可能详细介绍了脚本的编写过程,包括所使用的工具、必需的命令行参数、以及在反编译过程中可能遇到的问题和解决方案。常见的...
脚本化Java的一个重要应用是使用户能够自定义Java应用程序的行为,比如通过JavaScript来控制Firefox浏览器的用户界面。此外,Rhino解释器作为Java实现的JavaScript引擎,允许在Java应用程序中直接执行JavaScript代码...
附件中的 "JSP自定义标签.pdf" 暗示了与Java Web相关的知识,JSP(JavaServer Pages)是用于动态生成Web内容的一种技术。自定义标签允许开发者创建可复用的UI组件,它们扩展了JSP的表达能力,提供了一种封装复杂逻辑...
**SeaShell:在Java中构建自定义脚本语言的命令行shell** SeaShell是一个开源项目,它允许开发者在Java环境中创建一个自定义的命令行shell,这个shell可以支持多种脚本语言,使得用户能够通过命令行接口执行各种任务...
在Java编程环境中,验证脚本组件是一个至关重要的部分,它涉及到程序的安全性和数据的准确性。在Java中,验证脚本通常用于确保输入的数据符合预期的格式和规则,防止非法操作或者错误的数据进入系统。这样的脚本可以...
自定义脚本xsync.zip"聚焦于Hadoop中的一个重要实践——自定义脚本的使用,特别是名为"xsync"的脚本。通过学习这个脚本,我们可以深入了解如何在Hadoop环境中协调和管理数据。 在Hadoop生态系统中,数据通常分布在...