首页

基于alibaba的dubbo定义源码编译器Compiler及实现类JdkCompiler、JavassistCompiler源码解读分析

标签:dubbo,编译器,JdkCompiler,动态编译,实时编译,ide     发布时间:2017-12-03   

一、前言

这边基于alibaba的dubbo包中com.alibaba.dubbo.common.compiler自定义的编译器包,其中包括接口com.alibaba.dubbo.common.compiler.Compiler、抽象实现类com.alibaba.dubbo.common.compiler.AbstractCompiler及主要实现类com.alibaba.dubbo.common.compiler.JdkCompiler。

二、源码分析

1.Compiler接口定义

package com.alibaba.dubbo.common.compiler;@b@@b@import com.alibaba.dubbo.common.extension.SPI;@b@@b@@SPI("javassist")@b@public abstract interface Compiler@b@{@b@  public abstract Class<?> compile(String paramString, ClassLoader paramClassLoader);@b@}

2.AbstractCompiler抽象类

package com.alibaba.dubbo.common.compiler.support;@b@@b@import com.alibaba.dubbo.common.compiler.Compiler;@b@import com.alibaba.dubbo.common.utils.ClassHelper;@b@import java.util.regex.Matcher;@b@import java.util.regex.Pattern;@b@@b@public abstract class AbstractCompiler@b@  implements Compiler@b@{@b@  private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");@b@  private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");@b@@b@  public Class<?> compile(String code, ClassLoader classLoader)@b@  {@b@    String pkg;@b@    String cls;@b@    code = code.trim();@b@    Matcher matcher = PACKAGE_PATTERN.matcher(code);@b@@b@    if (matcher.find())@b@      pkg = matcher.group(1);@b@    else@b@      pkg = "";@b@@b@    matcher = CLASS_PATTERN.matcher(code);@b@@b@    if (matcher.find())@b@      cls = matcher.group(1);@b@    else@b@      throw new IllegalArgumentException("No such class name in " + code);@b@@b@    String className = ((pkg != null) && (pkg.length() > 0)) ? pkg + "." + cls : cls;@b@    try {@b@      return Class.forName(className, true, ClassHelper.getCallerClassLoader(super.getClass()));@b@    } catch (ClassNotFoundException e) {@b@      if (!(code.endsWith("}")))@b@        throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");@b@      try@b@      {@b@        return doCompile(className, code);@b@      } catch (RuntimeException t) {@b@        throw t;@b@      } catch (Throwable t) {@b@        throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));@b@      }@b@    }@b@  }@b@@b@  protected abstract Class<?> doCompile(String paramString1, String paramString2)@b@    throws Throwable;@b@}

3.主要实现类JdkCompiler

package com.alibaba.dubbo.common.compiler.support;@b@@b@import com.alibaba.dubbo.common.utils.ClassHelper;@b@import java.io.ByteArrayInputStream;@b@import java.io.ByteArrayOutputStream;@b@import java.io.File;@b@import java.io.IOException;@b@import java.io.InputStream;@b@import java.io.OutputStream;@b@import java.net.URI;@b@import java.net.URL;@b@import java.net.URLClassLoader;@b@import java.security.AccessController;@b@import java.security.PrivilegedAction;@b@import java.util.ArrayList;@b@import java.util.Arrays;@b@import java.util.Collection;@b@import java.util.Collections;@b@import java.util.Enumeration;@b@import java.util.HashMap;@b@import java.util.Iterator;@b@import java.util.List;@b@import java.util.Map;@b@import java.util.Set;@b@import javax.tools.DiagnosticCollector;@b@import javax.tools.FileObject;@b@import javax.tools.ForwardingJavaFileManager;@b@import javax.tools.JavaCompiler;@b@import javax.tools.JavaCompiler.CompilationTask;@b@import javax.tools.JavaFileManager;@b@import javax.tools.JavaFileManager.Location;@b@import javax.tools.JavaFileObject;@b@import javax.tools.JavaFileObject.Kind;@b@import javax.tools.SimpleJavaFileObject;@b@import javax.tools.StandardJavaFileManager;@b@import javax.tools.StandardLocation;@b@import javax.tools.ToolProvider;@b@@b@public class JdkCompiler extends AbstractCompiler@b@{@b@  private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();@b@  private final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector();@b@  private final ClassLoaderImpl classLoader;@b@  private final JavaFileManagerImpl javaFileManager;@b@  private volatile List<String> options;@b@@b@  public JdkCompiler()@b@  {@b@    this.options = new ArrayList();@b@    this.options.add("-target");@b@    this.options.add("1.6");@b@    StandardJavaFileManager manager = this.compiler.getStandardFileManager(this.diagnosticCollector, null, null);@b@    ClassLoader loader = Thread.currentThread().getContextClassLoader();@b@    if ((loader instanceof URLClassLoader) && (!(loader.getClass().getName().equals("sun.misc.Launcher$AppClassLoader"))))@b@      try@b@      {@b@        URLClassLoader urlClassLoader = (URLClassLoader)loader;@b@        List files = new ArrayList();@b@        URL[] arr$ = urlClassLoader.getURLs(); int len$ = arr$.length; for (int i$ = 0; i$ < len$; ++i$) { URL url = arr$[i$];@b@          files.add(new File(url.getFile()));@b@        }@b@        manager.setLocation(StandardLocation.CLASS_PATH, files);@b@      } catch (IOException e) {@b@        throw new IllegalStateException(e.getMessage(), e);@b@      }@b@@b@    this.classLoader = ((ClassLoaderImpl)AccessController.doPrivileged(new PrivilegedAction(this, loader) {@b@      public JdkCompiler.ClassLoaderImpl run() {@b@        return new JdkCompiler.ClassLoaderImpl(this.this$0, this.val$loader);@b@      }@b@@b@    }));@b@    this.javaFileManager = new JavaFileManagerImpl(manager, this.classLoader);@b@  }@b@@b@  public Class<?> doCompile(String name, String sourceCode) throws Throwable@b@  {@b@    int i = name.lastIndexOf(46);@b@    String packageName = (i < 0) ? "" : name.substring(0, i);@b@    String className = (i < 0) ? name : name.substring(i + 1);@b@    JavaFileObjectImpl javaFileObject = new JavaFileObjectImpl(className, sourceCode);@b@    this.javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName, className + ".java", javaFileObject);@b@@b@    Boolean result = this.compiler.getTask(null, this.javaFileManager, this.diagnosticCollector, this.options, null, Arrays.asList(new JavaFileObject[] { javaFileObject })).call();@b@@b@    if ((result == null) || (!(result.booleanValue())))@b@      throw new IllegalStateException("Compilation failed. class: " + name + ", diagnostics: " + this.diagnosticCollector);@b@@b@    return this.classLoader.loadClass(name);@b@  }@b@@b@  private static final class JavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {@b@    private final JdkCompiler.ClassLoaderImpl classLoader;@b@    private final Map<URI, JavaFileObject> fileObjects = new HashMap();@b@@b@    public JavaFileManagerImpl(JavaFileManager fileManager, JdkCompiler.ClassLoaderImpl classLoader) {@b@      super(fileManager);@b@      this.classLoader = classLoader;@b@    }@b@@b@    public FileObject getFileForInput(JavaFileManager.Location location, String packageName, String relativeName) throws IOException@b@    {@b@      FileObject o = (FileObject)this.fileObjects.get(uri(location, packageName, relativeName));@b@      if (o != null)@b@        return o;@b@      return super.getFileForInput(location, packageName, relativeName);@b@    }@b@@b@    public void putFileForInput(StandardLocation location, String packageName, String relativeName, JavaFileObject file) {@b@      this.fileObjects.put(uri(location, packageName, relativeName), file);@b@    }@b@@b@    private URI uri(JavaFileManager.Location location, String packageName, String relativeName) {@b@      return ClassUtils.toURI(location.getName() + '/' + packageName + '/' + relativeName);@b@    }@b@@b@    public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String qualifiedName, JavaFileObject.Kind kind, FileObject outputFile)@b@      throws IOException@b@    {@b@      JavaFileObject file = new JdkCompiler.JavaFileObjectImpl(qualifiedName, kind);@b@      this.classLoader.add(qualifiedName, file);@b@      return file;@b@    }@b@@b@    public ClassLoader getClassLoader(JavaFileManager.Location location)@b@    {@b@      return this.classLoader;@b@    }@b@@b@    public String inferBinaryName(JavaFileManager.Location loc, JavaFileObject file)@b@    {@b@      if (file instanceof JdkCompiler.JavaFileObjectImpl)@b@        return file.getName();@b@      return super.inferBinaryName(loc, file);@b@    }@b@@b@    public Iterable<JavaFileObject> list(JavaFileManager.Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse)@b@      throws IOException@b@    {@b@      JavaFileObject file;@b@      Iterable result = super.list(location, packageName, kinds, recurse);@b@@b@      ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();@b@      List urlList = new ArrayList();@b@      Enumeration e = contextClassLoader.getResources("com");@b@      while (e.hasMoreElements()) {@b@        urlList.add(e.nextElement());@b@      }@b@@b@      ArrayList files = new ArrayList();@b@@b@      if ((location == StandardLocation.CLASS_PATH) && (kinds.contains(JavaFileObject.Kind.CLASS))) {@b@        for (i$ = this.fileObjects.values().iterator(); i$.hasNext(); ) { file = (JavaFileObject)i$.next();@b@          if ((file.getKind() == JavaFileObject.Kind.CLASS) && (file.getName().startsWith(packageName)))@b@            files.add(file);@b@@b@        }@b@@b@        files.addAll(this.classLoader.files());@b@      } else if ((location == StandardLocation.SOURCE_PATH) && (kinds.contains(JavaFileObject.Kind.SOURCE))) {@b@        for (i$ = this.fileObjects.values().iterator(); i$.hasNext(); ) { file = (JavaFileObject)i$.next();@b@          if ((file.getKind() == JavaFileObject.Kind.SOURCE) && (file.getName().startsWith(packageName)))@b@            files.add(file);@b@        }@b@@b@      }@b@@b@      for (Iterator i$ = result.iterator(); i$.hasNext(); ) { file = (JavaFileObject)i$.next();@b@        files.add(file);@b@      }@b@@b@      return files;@b@    }@b@  }@b@@b@  private static final class JavaFileObjectImpl extends SimpleJavaFileObject@b@  {@b@    private ByteArrayOutputStream bytecode;@b@    private final CharSequence source;@b@@b@    public JavaFileObjectImpl(String baseName, CharSequence source)@b@    {@b@      super(ClassUtils.toURI(baseName + ".java"), JavaFileObject.Kind.SOURCE);@b@      this.source = source;@b@    }@b@@b@    JavaFileObjectImpl(String name, JavaFileObject.Kind kind) {@b@      super(ClassUtils.toURI(name), kind);@b@      this.source = null;@b@    }@b@@b@    public JavaFileObjectImpl(URI uri, JavaFileObject.Kind kind) {@b@      super(uri, kind);@b@      this.source = null;@b@    }@b@@b@    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws UnsupportedOperationException@b@    {@b@      if (this.source == null)@b@        throw new UnsupportedOperationException("source == null");@b@@b@      return this.source;@b@    }@b@@b@    public InputStream openInputStream()@b@    {@b@      return new ByteArrayInputStream(getByteCode());@b@    }@b@@b@    public OutputStream openOutputStream()@b@    {@b@      return (this.bytecode = new ByteArrayOutputStream());@b@    }@b@@b@    public byte[] getByteCode() {@b@      return this.bytecode.toByteArray();@b@    }@b@  }@b@@b@  private final class ClassLoaderImpl extends ClassLoader@b@  {@b@    private final Map<String, JavaFileObject> classes = new HashMap();@b@@b@    ClassLoaderImpl(, ClassLoader paramClassLoader)@b@    {@b@      super(parentClassLoader);@b@    }@b@@b@    Collection<JavaFileObject> files() {@b@      return Collections.unmodifiableCollection(this.classes.values());@b@    }@b@@b@    protected Class<?> findClass() throws ClassNotFoundException@b@    {@b@      JavaFileObject file = (JavaFileObject)this.classes.get(qualifiedClassName);@b@      if (file != null) {@b@        byte[] bytes = ((JdkCompiler.JavaFileObjectImpl)file).getByteCode();@b@        return defineClass(qualifiedClassName, bytes, 0, bytes.length);@b@      }@b@      try {@b@        return ClassHelper.forNameWithCallerClassLoader(qualifiedClassName, getClass()); } catch (ClassNotFoundException nf) {@b@      }@b@      return super.findClass(qualifiedClassName);@b@    }@b@@b@    void add(, JavaFileObject javaFile)@b@    {@b@      this.classes.put(qualifiedClassName, javaFile);@b@    }@b@@b@    protected synchronized Class<?> loadClass(, boolean resolve) throws ClassNotFoundException@b@    {@b@      return super.loadClass(name, resolve);@b@    }@b@@b@    public InputStream getResourceAsStream()@b@    {@b@      if (name.endsWith(".class")) {@b@        String qualifiedClassName = name.substring(0, name.length() - ".class".length()).replace('/', '.');@b@        JdkCompiler.JavaFileObjectImpl file = (JdkCompiler.JavaFileObjectImpl)this.classes.get(qualifiedClassName);@b@        if (file != null)@b@          return new ByteArrayInputStream(file.getByteCode());@b@      }@b@@b@      return super.getResourceAsStream(name);@b@    }@b@  }@b@}