All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ideaaedi.component.compile.DynamicClassLoader Maven / Gradle / Ivy

There is a newer version: 2.6.0
Show newest version
package com.ideaaedi.component.compile;

import lombok.extern.slf4j.Slf4j;

import javax.tools.JavaFileObject;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 自定义类加载器,用于加载{@link CharSequenceJavaFileObject}实例
 *
 * @author JustryDeng
 * @since 2021/9/20 16:30:44
 */
@Slf4j
public class DynamicClassLoader extends ClassLoader {
    
    /**
     * key - CharSequenceJavaFileObject所代表类的全类名
* value - CharSequenceJavaFileObject实例 */ private final Map javaFileObjectMap = new ConcurrentHashMap<>(16); /** * 假设现在我们要调用{@link DynamicClassLoader#findClass(String)}方法,defineClass两个类
* public class TestLogger1
* 和
* public class TestLogger2 extends TestLogger1时,
*

* 当先defineClass的是TestLogger2时,由于TestLogger2中用到了TestLogger1,那么defineClass方法内部就自动调用对TestLogger1的defineClass,
* 此时,调用findClass方法的调用者只收到了TestLogger2的Class实例,如果调用者不知道TestLogger2中有TestLogger1(即:不知道TestLogger1已经被
* defineClass了的话),调用者再主动对TestLogger1进行findClass时,就会因为重复defineClass,而报错:
* Caused by: java.lang.LinkageError: loader (instance of com/ideaaedi/hot/clazz/compile/DynamicClassLoader): attempted duplicate class definition for name: "com/test/TestLogger1"
*

* currDefinedClass参数就是来解决这个问题的 */ private final Map> currDefinedClass = new ConcurrentHashMap<>(8); public DynamicClassLoader(ClassLoader parentClassLoader) { super(parentClassLoader); } @Override protected Class findClass(String classLongName) throws ClassNotFoundException { CharSequenceJavaFileObject javaFileObject = javaFileObjectMap.get(classLongName); if (javaFileObject != null) { byte[] byteCode = javaFileObject.getByteCode(); Class klass = defineClass(classLongName, byteCode, 0, byteCode.length); log.info("defineClass {} complement.", classLongName); currDefinedClass.put(classLongName, klass); return klass; } return super.findClass(classLongName); } @Override public InputStream getResourceAsStream(String name) { if (name.endsWith(JavaFileObject.Kind.CLASS.extension)) { String classLongNameWithoutSuffix = name.substring(0, name.length() - JavaFileObject.Kind.CLASS.extension.length()).replace('/', '.'); CharSequenceJavaFileObject javaFileObject = javaFileObjectMap.get(classLongNameWithoutSuffix); if (javaFileObject != null && javaFileObject.getByteCode() != null) { return new ByteArrayInputStream(javaFileObject.getByteCode()); } } return super.getResourceAsStream(name); } /** * 存 */ public void registerCompiledSource(String classLongName, CharSequenceJavaFileObject javaFileObject) { javaFileObjectMap.put(classLongName, javaFileObject); } /** * 罗列 */ public Collection listCharSequenceJavaFileObject() { return Collections.unmodifiableCollection(javaFileObjectMap.values()); } /** * 获取所有已加载的class
* key - 全类名
* value - class实例 */ public Map> getClasses() throws ClassNotFoundException { Map> classes = new HashMap<>(16); for (CharSequenceJavaFileObject byteCode : javaFileObjectMap.values()) { String classLongName = byteCode.getName(); if (classes.containsKey(classLongName)) { log.info("classLongName already been defined."); continue; } Class klass = findClass(classLongName); classes.putAll(currDefinedClass); classes.put(classLongName, klass); currDefinedClass.clear(); } return classes; } /** * 获取所有已加载的class
* key - 全类名
* value - .class文件字节码 */ public Map getByteCodes() { Map result = new HashMap<>(javaFileObjectMap.size()); for (Map.Entry entry : javaFileObjectMap.entrySet()) { result.put(entry.getKey(), entry.getValue().getByteCode()); } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy