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; } }}
阅读全文
0 0
- Dubbo入门学习--动态代码编译器Compiler
- dubbo入门实例代码
- Dubbo学习入门(一)
- dubbo入门学习笔记
- Dubbo入门学习记录
- Dubbo入门学习笔记
- Dubbo学习(一)入门
- Dubbo入门学习
- Dubbo 学习入门(一)
- Dubbo入门学习--Dubbo简单示例
- dubbo系统学习(一)-dubbo入门实例
- dubbo入门学习之Helloworld
- dubbo入门官方案例学习
- angularjs compiler编译器
- 编译器设计: naive compiler
- Linux入门学习-gcc编译器与静态动态链接_第五章
- [dubbo入门] dubbo入门
- dubbo学习笔记 九 dubbo-common之动态扩展extension
- Git进阶【一】
- leetcode 69 implement the sqrt(x)
- 我的csdn博客开通了
- 51采集PCF8591数据通过ESP8266上传C#上位机
- Android-记账本(四)-适配器和CostBean类
- Dubbo入门学习--动态代码编译器Compiler
- MySQL学习篇一校对规则
- 一起艳学Centos7(二)
- Node.js模块的概念
- ajax跟跨域
- java面经整理(3)
- 简述Spring容器与SpringMVC的容器的联系与区别
- Android-记账本(五)- 数据库
- Android-记账本(六)- ChatActivity