Java核心技术之脚本和编译

来源:互联网 发布:健身理论 知乎 编辑:程序博客网 时间:2024/06/09 19:41

脚本

//创建一个脚本引擎管理器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.YELLOWblueButton.action=panel.background = java.awt.Color.BLUEredButton.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 0
原创粉丝点击