Java核心技术之脚本和编译

脚本

//创建一个脚本引擎管理器
ScriptEngineManager manager = new ScriptEngineManager();

//遍历引擎管理器所支持的所有脚本引擎
for (ScriptEngineFactory factory : manager.getEngineFactories()) {
    System.out.println(factory.getEngineName());
}

//根据引擎名字获取一个脚本引擎对象
final ScriptEngine engine = manager.getEngineByName("js");

//构造一个JFrame对象,里面包含一个JPanel和三个JButton对象
JFrame frame = (JFrame) Class.forName("buttons1.ButtonFrame").newInstance();

//向引擎对象中添加绑定(Bean的名字和实例的映射),这样在脚本的执行上下文中就可以访问Java对象(上面的UI对象)
private static void getComponentBindings(Component c, ScriptEngine engine) {
    String name = c.getName();
    if (name != null) engine.put(name, c);
    if (c instanceof Container) {
        for (Component child : ((Container) c).getComponents())
            getComponentBindings(child, engine);
    }
}

getComponentBindings(frame, engine);

//加载配置文件js.properties
/*
yellowButton.action=panel.background = java.awt.Color.YELLOW
blueButton.action=panel.background = java.awt.Color.BLUE
redButton.action=panel.background = java.awt.Color.RED
*/

final Properties events = new Properties();
InputStream in = frame.getClass().getResourceAsStream("js.properties");
events.load(in);

//根据配置文件设置三个按钮的点击监听器,监听器里面使用脚本引擎解析执行配置文件中相应JavaScript语句(第一个等号后面的内容)
for (final Object e : events.keySet()) {
    String[] s = ((String) e).split("\\.");
    addListener(s[0], s[1], (String) events.get(e), engine);
}

private static void addListener(String beanName, String eventName, final String scriptCode,
    final ScriptEngine engine) throws ReflectiveOperationException, IntrospectionException {
    Object bean = engine.get(beanName);
    EventSetDescriptor descriptor = getEventSetDescriptor(bean, eventName);
    if (descriptor == null) return;
    //使用动态代理生成一个对象
    descriptor.getAddListenerMethod().invoke(bean, Proxy.newProxyInstance(null, new Class[] { descriptor.getListenerType() }, 
        new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
                //解析JavaScript脚本
                engine.eval(scriptCode);
                return null;
            }
        }
    ));
}

private static EventSetDescriptor getEventSetDescriptor(Object bean, String eventName) throws IntrospectionException{
    for (EventSetDescriptor descriptor : Introspector.getBeanInfo(bean.getClass()).getEventSetDescriptors())
        if (descriptor.getName().equals(eventName)) return descriptor;
    return null;
}

编译

动态生成类

//构造一个JavaFileObject对象,用于编译
JavaFileObject source = buildSource("buttons2.ButtonFrame");
//动态生成了一个继承于buttons2.ButtonFrame的类x.Frame(包括包名)
static JavaFileObject buildSource(String superclassName) throws IOException, ClassNotFoundException {
    StringBuilderJavaSource source = new StringBuilderJavaSource("x.Frame");
    source.append("package x;\n");
    source.append("public class Frame extends " + superclassName + " {");
    source.append("protected void addEventHandlers() {");
    final Properties props = new Properties();
    props.load(Class.forName(superclassName).getResourceAsStream("action.properties"));
    for (Map.Entry<Object, Object> e : props.entrySet()) {
        String beanName = (String) e.getKey();
        String eventCode = (String) e.getValue();
        source.append(beanName + ".addActionListener(new java.awt.event.ActionListener() {");
        source.append("public void actionPerformed(java.awt.event.ActionEvent event) {");
        source.append(eventCode);
        source.append("} } );");
    }
    source.append("} }");
    return source;
}

//StringBuilderJavaSource类扩展了SimpleJavaFileObject类,如下:
public class StringBuilderJavaSource extends SimpleJavaFileObject {
    private StringBuilder code;

    public StringBuilderJavaSource(String name) {
        super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
        code = new StringBuilder();
    }

    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }

    public void append(String str) {
        code.append(str);
        code.append('\n');
    }
}

编译类

//用于存放编译后的结果
final List<ByteArrayJavaClass> classFileObjects = new ArrayList<>();
//编译器诊断输出对象
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
//JavaFileManager对象,将结果放入classFileObjects数组
JavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
fileManager = new ForwardingJavaFileManager<JavaFileManager>(fileManager) {
    public JavaFileObject getJavaFileForOutput(Location location, final String className,
                                               Kind kind, FileObject sibling) throws IOException {
        if (className.startsWith("x.")) {
            ByteArrayJavaClass fileObject = new ByteArrayJavaClass(className);
            classFileObjects.add(fileObject);
            return fileObject;
        } else return super.getJavaFileForOutput(location, className, kind, sibling);
    }
};
//ByteArrayJavaClass类如下
public class ByteArrayJavaClass extends SimpleJavaFileObject {
    private ByteArrayOutputStream stream;

    public ByteArrayJavaClass(String name) {
        super(URI.create("bytes:///" + name), Kind.CLASS);
        stream = new ByteArrayOutputStream();
    }

    public OutputStream openOutputStream() throws IOException {
        return stream;
    }

    public byte[] getBytes() {
        return stream.toByteArray();
    }
}

//获取一个编译器对象
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

//创建一个编译任务并开始编译        
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, Arrays.asList(source));
boolean result = task.call();

使用类

//使用编译后的类集合构造一个自定义的ClassLoader,然后加载类x.Frame,并构造一个Frame的对象。
Map<String, byte[]> byteCodeMap = new HashMap<>();
for (ByteArrayJavaClass cl : classFileObjects)
    byteCodeMap.put(cl.getName().substring(1), cl.getBytes());
ClassLoader loader = new MapClassLoader(byteCodeMap);
JFrame frame = (JFrame) loader.loadClass("x.Frame").newInstance();

//最后自定义的MapClassLoader如下:
public class MapClassLoader extends ClassLoader {
    private Map<String, byte[]> classes;

    public MapClassLoader(Map<String, byte[]> classes) {
        this.classes = classes;
    }

    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classBytes = classes.get(name);
        if (classBytes == null) throw new ClassNotFoundException(name);
        Class<?> cl = defineClass(name, classBytes, 0, classBytes.length);
        if (cl == null) throw new ClassNotFoundException(name);
        return cl;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值