Dubbo入门学习--动态代码编译器Compiler

来源:互联网 发布:mac怎么打开mobi文件 编辑:程序博客网 时间:2024/06/16 18:13

在之前一篇博客中Dubbo入门学习--SPI实现@SPI和@Adaptive,我们已经了解到Dubbo通过生成动态代码来实现动态代理的,Dubbo提供了动态代码编译器接口Compiler。

Compiler接口:

@SPI("javassist")public interface Compiler {/** * Compile java source code. *  * @param code Java source code * @param classLoader TODO * @return Compiled class */Class<?> compile(String code, ClassLoader classLoader);}

Compiler接口提供了一个compile方法:
(1)code : 动态代码字符串
(2)classLoader :类加载器


Compiler接口实现类结构:


AdaptiveCompiler :简单来说是一个适配器类,通过参数来选择使用JdkCompiler还是JavassistCompiler

@Adaptivepublic class AdaptiveCompiler implements Compiler {//从配置文件中读取字符串    private static volatile String DEFAULT_COMPILER;    public static void setDefaultCompiler(String compiler) {        DEFAULT_COMPILER = compiler;    }    public Class<?> compile(String code, ClassLoader classLoader) {        Compiler compiler;        ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);        String name = DEFAULT_COMPILER; // copy reference//选择使用默认JavassistCompiler还是JdkCompiler        if (name != null && name.length() > 0) {            compiler = loader.getExtension(name);        } else {            compiler = loader.getDefaultExtension();        }        return compiler.compile(code, classLoader);    }}
JavassistCompiler:使用Javassist提供的动态代码编译功能

public class JavassistCompiler extends AbstractCompiler {    private static final Pattern IMPORT_PATTERN = Pattern.compile("import\\s+([\\w\\.\\*]+);\n");    private static final Pattern EXTENDS_PATTERN = Pattern.compile("\\s+extends\\s+([\\w\\.]+)[^\\{]*\\{\n");    private static final Pattern IMPLEMENTS_PATTERN = Pattern.compile("\\s+implements\\s+([\\w\\.]+)\\s*\\{\n");        private static final Pattern METHODS_PATTERN = Pattern.compile("\n(private|public|protected)\\s+");    private static final Pattern FIELD_PATTERN = Pattern.compile("[^\n]+=[^\n]+;");    @Override    public Class<?> doCompile(String name, String source) throws Throwable {        int i = name.lastIndexOf('.');        String className = i < 0 ? name : name.substring(i + 1);        ClassPool pool = new ClassPool(true);        pool.appendClassPath(new LoaderClassPath(ClassHelper.getCallerClassLoader(getClass())));        Matcher matcher = IMPORT_PATTERN.matcher(source);        List<String> importPackages = new ArrayList<String>();        Map<String, String> fullNames = new HashMap<String, String>();        while (matcher.find()) {            String pkg = matcher.group(1);            if (pkg.endsWith(".*")) {                String pkgName = pkg.substring(0, pkg.length() - 2);                pool.importPackage(pkgName);                importPackages.add(pkgName);            } else {                int pi = pkg.lastIndexOf('.');                if (pi > 0) {                String pkgName = pkg.substring(0, pi);                pool.importPackage(pkgName);                importPackages.add(pkgName);                fullNames.put(pkg.substring(pi + 1), pkg);                }            }        }        String[] packages = importPackages.toArray(new String[0]);        matcher = EXTENDS_PATTERN.matcher(source);        CtClass cls;        if (matcher.find()) {            String extend = matcher.group(1).trim();            String extendClass;            if (extend.contains(".")) {                extendClass = extend;            } else if (fullNames.containsKey(extend)) {                extendClass = fullNames.get(extend);            } else {                extendClass = ClassUtils.forName(packages, extend).getName();            }            cls = pool.makeClass(name, pool.get(extendClass));        } else {            cls = pool.makeClass(name);        }        matcher = IMPLEMENTS_PATTERN.matcher(source);        if (matcher.find()) {            String[] ifaces = matcher.group(1).trim().split("\\,");            for (String iface : ifaces) {                iface = iface.trim();                String ifaceClass;                if (iface.contains(".")) {                    ifaceClass = iface;                } else if (fullNames.containsKey(iface)) {                    ifaceClass = fullNames.get(iface);                } else {                    ifaceClass = ClassUtils.forName(packages, iface).getName();                }                cls.addInterface(pool.get(ifaceClass));            }        }        String body = source.substring(source.indexOf("{") + 1, source.length() - 1);        String[] methods = METHODS_PATTERN.split(body);        for (String method : methods) {            method = method.trim();            if (method.length() > 0) {                if (method.startsWith(className)) {                    cls.addConstructor(CtNewConstructor.make("public " + method, cls));                } else if (FIELD_PATTERN.matcher(method).matches()) {                    cls.addField(CtField.make("private " + method, cls));                } else {                    cls.addMethod(CtNewMethod.make("public " + method, cls));                }            }        }        return cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());    }}



JdkCompiler:使用JDK提供的动态代码编译功能

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




原创粉丝点击