`

java 自定义动态脚本

阅读更多

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());
            }
        }
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

    自定义添加linux系统java环境变量脚本及安装包

    本资源为二狗自己编写的快速定义java环境变量的脚本,可以帮助你剩下不少时间,操作前建议备份/etc/profile文件:mv /etc/profile{,.bak} 防止脚本问题覆盖掉文件的内容 资源分为脚本和安装包两部分内容,放置在同一...

    为marc数据自定义处理脚本--PxMarcScript_0.1

    为marc数据自定义处理脚本,脚本支持groovy或java语言。 需JAVA 1.6以上,直接运行jar文件或bat文件即可。 联系作者:444057137@qq.com

    SeaShell:在 Java 中使用自定义脚本语言的自定义命令行 shell

    贝壳在 Java 中使用自定义脚本语言的自定义命令行 shell

    cognos自定义JAVA权限认证

    cognos自定义java程序登录程序,文件包含sql脚本,jar包,源码文档等。测试在cognos上登录可用,实现cognos自定义用户表权限管理。

    JAVA抽奖活动大转盘(含前后端源码、数据库脚本, 抽奖算法)支持一键运行

    1、采用Java语言开发,集成SpringBoot,Redis、Mybatis,SpringEvent、Maven,项目 2、包含前端、后端源码,数据库设计、SQL脚本,抽奖算法如果没有实现思路,这是一个很好的入门案例。

    Java脚本引擎1

    (1)java中获取脚本引擎的方法:获取js引擎:(2)脚本执行时的数据绑定对象:可以自定义一个binding对象:(有两个例子,可以对比一下)脚本执行引擎上下

    吴天雄-Java注解及动态性详解.doc

    本文档内容包括: 1.注解详细内容(五个内置注解、...2.java动态性(静态语言、动态语言、反射机制操作(类、属性、注解、构造器)、动态编译、脚本引擎Rhino动态执行JavaScript代码、动态Java字节码操作) --author:

    自定义 Graal - MetaTrader 4脚本.zip

    自定义 Graal 指标.

    Spring MVC- 微信公众号开发之自定义菜单开发SQL脚本

    java版微信公众号开发之自定义菜单的创建代码中使用的SQL,创建自定义菜单的代码链接:https://www.blog-china.cn/liuzaiqingshan/home/10/1519376790015

    deelang:适用于Android的轻量级动态脚本语言

    德朗是: 灵活:您可以轻松地嵌入Deelang并为您的用户提供自定义脚本环境。 轻量级:整个Deelang编译器,VM和运行时的重量都小于1MB(包括所需的ANTLR运行时)。 在Android上,使用novm jar将为您的APK添加约300k。 ...

    java script 调试工具 脚本控制台

    WEB 开发人员的得力工具,只需要在网页中嵌入一个js文件,即使在模式对话框中,也一样方便在线查看网页源码,javascript变量,在页面上执行自定义脚本,即写即运行,不影响被调试页面的外观。 主要功能: 变量 ...

    java源码包---java 源码 大量 实例

    Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP  Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...

    深入了解Java 脚本化api编程

    Java 脚本 API 是一种独立于框架的脚本语言,使用来自于Java代码的脚本引擎 。可以使用Java语言编写定制/可扩展的应用程序并将自定义脚本语言选择留给最终用户 。下面我们来详细了解一下吧

    magic-script是一款基于JVM的脚本语言,目前主要是为magic-api项目设计

    magic-script是一款基于JVM的脚本语言,目前主要是为magic-api项目设计。magic-api,接口快速开发框架,通过Web页面配置,自动映射为HTTP接口;spider-flow,新一代爬虫平台,以图形化方式定义爬虫流程,不写代码...

    JAVA自定义注解在自动化测试中的使用

    在UI自动化测试中,相信很多人都喜欢用所谓的PO模式,其中的P,也是page的意思,于是乎,在脚本里,或者在其它的page里,会要new很多的page对象,这样很麻烦,前面我们也讲到了注解的使用,很方便,那么我们可不可以...

    完整版Java JSP web开发教程 10_自定义标签(共20页).ppt

    完整版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开发者...

    简单Web服务器(Java实现)

    这是《计算机网络》的...要支持PHP的动态脚本的话,需要自行下载PHP的文件到php目录下,并且更改设置,开启PHP的CGI模式。(请先看下里面的"说明.txt")(温馨提示:下载后评论【需要评选等级】会返回被扣除的积分)

    JAVA上百实例源码以及开源项目

    Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP  Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...

    JAVA上百实例源码以及开源项目源代码

    Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP  Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...

Global site tag (gtag.js) - Google Analytics