目录
- 1、加载机制概述
- 1.1 Java SPI
- 1.2 Dubbo SPI
- 1.3 扩展点的配置规范
- 1.4 扩展点的分类与缓存
- 1.5 扩展点的特性
- 2、扩展点注解
- 2.1 @SPI 注解
- 2.2 @Adaptive 注解
- 2.3 @Activate 注解
- 3、ExtensionLoader 的工作原理
- 3.1 getExtension的实现原理
- 3.2 getAdaptiveExtension的实现原理
- 3.3 getActivateExtension的实现原理
- 4、扩展点动态编译的实现
- 4.1 Javassist动态代码编译
- 4.2 JDK动态代码编译
1、加载机制概述
Dubbo SPI没有直接使用Java SPI,在它的思想上又做了一定的改进,形成了一套自己的配置规范和特性,同时又兼容Java SPI
1.1 Java SPI
具体参考 Java SPI
1.2 Dubbo SPI
具体参考 Dubbo SPI
1.3 扩展点的配置规范
Dubbo SPI和Java SPI类似,需要在META-INF/dubbo/下放置对应的SPI配置文件,文件名称需要命名为接口的全路径名。配置文件的内容为key=扩展点实现类全路径名,如果有多个实现类则使用换行符分隔。在Dubbo启动的时候,会默认扫这三个目录下的配置文件:META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/,如表所示:
规范名 | 规范说明 |
SPI配置文件路径 | META-INF/services/、 META-INF/dubbo/、 META-INF/dubbo/intemal/ |
SPI配置文件名称 | 全路径类名 |
文件内容格式 | key=value方式,多个用换行符分隔 |
1.4 扩展点的分类与缓存
Dubbo SPI可以分为Class缓存、实例缓存,这两种缓存能根据扩展类的种类分为普通扩展类、包装扩展类(Wrapper类)、自适应扩展类(Adaptive类)等
- Class缓存:Dubbo SPI获取扩展类时,会先从缓存中读取。如果缓存中不存在,则加载配置文件,根据配置把Class缓存到内存中,并不会直接全部初始化
- 实例缓存:Dubbo框架中不仅缓存Class,也会缓存Class实例化后的对象。每次获取的时候,会先从缓存中读取,如果缓存中读不到,则重新加载并缓存起来。
1.5 扩展点的特性
- 自动包装:ExtensionLoader在加载扩展时,如果发现这个扩展类包含其他扩展点作为构造函数的参数,则这个扩展类就会被认为是Wrapper类
- 自动加载:如果某个扩展类是另外一个扩展点类的成员属性,并且拥有setter方法,那么框架也会自动注入对应的扩展点实例,ExtensionLoader在执行扩展点初始化的时候,会自动通过setter方法注入对应的实现类
- 自适应:使用 @Adaptive 注解,可以动态地通过URL中的参数来确定要使用哪个具体的实现类。从而解决自动加载中的实例注入问题
- 自动激活:使用 @Activate 注解,可以标记对应的扩展点默认被激活启用。该注解还可以通过传入不同的参数,设置扩展点在不同的条件下被自动激活
2、扩展点注解
2.1 @SPI 注解
@SPI注解可以使用在类、接口和枚举类上,主要作用就是标记这个接口是一个Dubbo SPI接口,即是一个扩展点,可以有多个不同的内置或用户定义的实现。@SPI注解的代码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
// default extension name
String value() default "";
// scope of SPI, default value is application scope.
ExtensionScope scope() default ExtensionScope.APPLICATION;
}
通过value属性,以传入不同的参数来设置这个接口的默认实现类!
2.2 @Adaptive 注解
@Adaptive 注解可以标记在类、接口、枚举类和方法上,Dubbo框架中几乎都标注在方法上,即方法级别注解,则可以通过参数动态获得实现类,方法级别注解在第一次getExtensionLoader时,会自动生成和编译一个动态的Adaptive类,从而达到动态实现类的效果。Adaptive注解的代码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
String[] value() default {};
}
该注解也可以传入value参数,是一个数组。可以传入多个key值,在初始化Adaptive注解的接口时,会先对传入的URL进行key值匹配,第一个key没匹配上则匹配第二个,以此类推。直到所有的key匹配完毕,如果还没有匹配到, 则会使用“驼峰规则”匹配,如果也没匹配到,则会抛出IllegalStateException异常。
2.3 @Activate 注解
@Activate可以标记在类、接口、枚举类和方法上。主要使用在有多个扩展点实现、需要根据不同条件被激活的场景中,Activate 注解的代码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
// URL中的分组如果匹配则激活,则可以设置多个
String[] group() default {};
// 查找URL中如果含有该key值,则会激活
String[] value() default {};
/**
* 表示哪些扩展点要在本扩展点之前
* Deprecated since 2.7.0
*/
@Deprecated
String[] before() default {};
/**
* 表示哪些扩展点要在本扩展点之后
* Deprecated since 2.7.0
*/
@Deprecated
String[] after() default {};
// 整型,直接的排序信息,数值越小越先加载
int order() default 0;
}
3、ExtensionLoader 的工作原理
ExtensionLoader是整个扩展机制的主要逻辑类,在这个类里面实现了配置的加载、扩展类缓存、自适应对象生成等所有工作。
ExtensionLoader 的逻辑入口可以分为 getExtension、getAdaptiveExtension、getActivateExtension三个,分别是获取普通扩展类、获取自适应扩展类、获取自动激活的扩展类。ExtensionLoader 总体加载流程如下:
3.1 getExtension的实现原理
当调用getExtension(String name)方法时,会先检查缓存中是否有现成的数据,没有则调用createExtension开始创建,核心代码如下:
// 获取普通扩展类
public T getExtension(String name) {
T extension = getExtension(name, true);
if (extension == null) {
throw new IllegalArgumentException("Not find extension: " + name);
}
return extension;
}
public T getExtension(String name, boolean wrap) {
······
// 缓存中获取
final Holder<Object> holder = getOrCreateHolder(cacheKey);
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
// 缓存没有则创建
if (instance == null) {
instance = createExtension(name, wrap);
holder.set(instance);
}
}
}
return (T) instance;
}
private T createExtension(String name, boolean wrap) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
T instance = (T) extensionInstances.get(clazz);
if (instance == null) {
extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
instance = (T) extensionInstances.get(clazz);
instance = postProcessBeforeInitialization(instance, name);
injectExtension(instance);
instance = postProcessAfterInitialization(instance, name);
}
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
boolean match = (wrapper == null) ||
((ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) &&
!ArrayUtils.contains(wrapper.mismatches(), name));
if (match) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
instance = postProcessAfterInitialization(instance, name);
}
}
}
}
// Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle instance, this application may not invoke the lifecycle.initialize hook.
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
在调用createExtension开始创建的过程中,也会先检查缓存中是否有配置信息,如果不存在扩展类,则会从 META-INF/services/> META-INF/dubbo/、META-INF/dubbo/internal/这几个路径中读取所有的配置文件,通过I/O读取字符流,然后通过解析字符串,得到配置文件中对应的扩展点实现类的全称。
扩展点配置信息加载过程:
private Map<String, Class<?>> getExtensionClasses() {
// 1、先尝试从缓存中获取classes
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
try {
// 2、开始加载Class
classes = loadExtensionClasses();
} catch (InterruptedException e) {
logger.error("Exception occurred when loading extension class (interface: " + type + ")", e);
throw new IllegalStateException("Exception occurred when loading extension class (interface: " + type + ")", e);
}
cachedClasses.set(classes);
}
}
}
return classes;
}
private Map<String, Class<?>> loadExtensionClasses() throws InterruptedException {
······
for (LoadingStrategy strategy : strategies) {
// 3、加载路径下面的SPI配置文件
loadDirectory(extensionClasses, strategy, type.getName());
// compatible with old ExtensionFactory
if (this.type == ExtensionInjector.class) {
loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());
}
}
return extensionClasses;
}
private void loadDirectory(Map<String, Class<?>> extensionClasses, LoadingStrategy strategy, String type) throws InterruptedException {
// 加载配置
loadDirectoryInternal(extensionClasses, strategy, type);
try {
String oldType = type.replace("org.apache", "com.alibaba");
if (oldType.equals(type)) {
return;
}
//if class not found,skip try to load resources
ClassUtils.forName(oldType);
loadDirectoryInternal(extensionClasses, strategy, oldType);
} catch (ClassNotFoundException classNotFoundException) {
}
}
private void loadDirectoryInternal(Map<String, Class<?>> extensionClasses, LoadingStrategy loadingStrategy, String type) throws InterruptedException {
String fileName = loadingStrategy.directory() + type;
try {
List<ClassLoader> classLoadersToLoad = new LinkedList<>();
// try to load from ExtensionLoader's ClassLoader first
if (loadingStrategy.preferExtensionClassLoader()) {
ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
classLoadersToLoad.add(extensionLoaderClassLoader);
}
}
if (specialSPILoadingStrategyMap.containsKey(type)){
String internalDirectoryType = specialSPILoadingStrategyMap.get(type);
//skip to load spi when name don't match
if (!LoadingStrategy.ALL.equals(internalDirectoryType)
&& !internalDirectoryType.equals(loadingStrategy.getName())){
return;
}
classLoadersToLoad.clear();
classLoadersToLoad.add(ExtensionLoader.class.getClassLoader());
}else {
// load from scope model
Set<ClassLoader> classLoaders = scopeModel.getClassLoaders();
if (CollectionUtils.isEmpty(classLoaders)) {
// 通过 getSystemResources 得到配置文件
Enumeration<java.net.URL> resources = ClassLoader.getSystemResources(fileName);
if (resources != null) {
while (resources.hasMoreElements()) {
// 循环遍历urls,解析字符串,得到扩展实现类,并加入缓存
loadResource(extensionClasses, null, resources.nextElement(), loadingStrategy.overridden(),
loadingStrategy.includedPackages(),
loadingStrategy.excludedPackages(),
loadingStrategy.onlyExtensionClassLoaderPackages());
}
}
} else {
classLoadersToLoad.addAll(classLoaders);
}
}
//通过 loadResources 得到配置文件
Map<ClassLoader, Set<java.net.URL>> resources = ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad);
// 循环遍历urls,解析字符串,得到扩展实现类,并加入缓存
resources.forEach(((classLoader, urls) -> {
loadFromClass(extensionClasses, loadingStrategy.overridden(), urls, classLoader,
loadingStrategy.includedPackages(),
loadingStrategy.excludedPackages(),
loadingStrategy.onlyExtensionClassLoaderPackages());
}));
} catch (InterruptedException e) {
throw e;
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
加载完扩展点配置后,再通过反射获得所有扩展实现类并缓存起来,此处仅仅是把Class加载到JVM中,但并没有做Class初始化。扩展类的缓存分类核心代码:
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,boolean overridden) {
······
if (clazz.isAnnotationPresent(Adaptive.class)) {
// 如果是自适应类(Adaptive )则缓存,缓存的自适应类只能有一个
cacheAdaptiveClass(clazz, overridden);
} else if (isWrapperClass(clazz)) {
// 如果是包装扩展类(Wrapper),则直接加入包装扩展类的Set集合
if (cachedWrapperClasses == null) {
cachedWrapperClasses = new ConcurrentHashSet<>();
}
cachedWrapperClasses.add(clazz);
} else {
if (StringUtils.isEmpty(name)) {
name = findAnnotationName(clazz);
if (name.length() == 0) {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
}
}
String[] names = NAME_SEPARATOR.split(name);
if (ArrayUtils.isNotEmpty(names)) {
// 有自动激活注解(Activate),则缓存到自动激活的缓存中
cacheActivateClass(clazz, names[0]);
for (String n : names) {
// 缓存普通扩展类
cacheName(clazz, n);
saveInExtensionClass(extensionClasses, clazz, n, overridden);
}
}
}
}
3.2 getAdaptiveExtension的实现原理
在getAdaptiveExtension()方法中,会为扩展点接口自动生成实现类字符串,实现类主要包含以下逻辑:为接口中每个有@Adaptive注解的方法生成默认实现(没有注解的方法则生成空实现),每个默认实现都会从URL中提取Adaptive参数值,并
以此为依据动态加载扩展点。然后,框架会使用不同的编译器,把实现类字符串编译为自适应类并返回。大致流程如下:
// 获取自适应扩展类
@SuppressWarnings("unchecked")
public T getAdaptiveExtension() {
checkDestroyed();
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
········
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 缓存没有则创建
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}
private T createAdaptiveExtension() {
try {
T instance = (T) getAdaptiveExtensionClass().newInstance();
········
return instance;
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
private Class<?> createAdaptiveExtensionClass() {
// Adaptive Classes' ClassLoader should be the same with Real SPI interface classes' ClassLoader
ClassLoader classLoader = type.getClassLoader();
try {
if (NativeUtils.isNative()) {
return classLoader.loadClass(type.getName() + "$Adaptive");
}
} catch (Throwable ignore) {
}
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
org.apache.dubbo.common.compiler.Compiler compiler = extensionDirector.getExtensionLoader(
org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
// 生成实现类
return compiler.compile(type, code, classLoader);
}
@Adaptive注解是加在实现类AdaptiveCompiler上的。这样一来AdaptiveCompiler就会作为该自适应类的默认实现,不需要再做代码生成和编译就可以使用了
3.3 getActivateExtension的实现原理
getActivateExtension(URL url, String[] values, String group)方法可以获取所有自动激活扩展点。主流程分为4步:
- 检查缓存,如果缓存中没有,则初始化所有扩展类实现的集合
- 遍历整个©Activate注解集合,根据传入URL匹配条件(匹配group、name等),得到所有符合激活条件的扩展类实现,然后根据@©Activate中配置的before、after、order等参数进行排序
- 遍历所有用户自定义扩展类名称,根据用户URL配置的顺序,调整扩展点激活顺序
- 返回所有自动激活类集合
@SuppressWarnings("deprecation")
public List<T> getActivateExtension(URL url, String[] values, String group) {
checkDestroyed();
// solve the bug of using @SPI's wrapper method to report a null pointer exception.
Map<Class<?>, T> activateExtensionsMap = new TreeMap<>(activateComparator);
List<String> names = values == null ? new ArrayList<>(0) : asList(values);
Set<String> namesSet = new HashSet<>(names);
// URL的参数不包含 -default 才会激活
if (!namesSet.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
if (cachedActivateGroups.size() == 0) {
synchronized (cachedActivateGroups) {
// cache all extensions
if (cachedActivateGroups.size() == 0) {
getExtensionClasses();
for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Object activate = entry.getValue();
String[] activateGroup, activateValue;
if (activate instanceof Activate) {
activateGroup = ((Activate) activate).group();
activateValue = ((Activate) activate).value();
} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
} else {
continue;
}
cachedActivateGroups.put(name, new HashSet<>(Arrays.asList(activateGroup)));
String[][] keyPairs = new String[activateValue.length][];
for (int i = 0; i < activateValue.length; i++) {
if (activateValue[i].contains(":")) {
keyPairs[i] = new String[2];
String[] arr = activateValue[i].split(":");
keyPairs[i][0] = arr[0];
keyPairs[i][1] = arr[1];
} else {
keyPairs[i] = new String[1];
keyPairs[i][0] = activateValue[i];
}
}
cachedActivateValues.put(name, keyPairs);
}
}
}
}
// traverse all cached extensions
cachedActivateGroups.forEach((name, activateGroup) -> {
if (isMatchGroup(group, activateGroup)
&& !namesSet.contains(name)
&& !namesSet.contains(REMOVE_VALUE_PREFIX + name)
&& isActive(cachedActivateValues.get(name), url)) {
activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
}
});
}
if (namesSet.contains(DEFAULT_KEY)) {
// will affect order
// `ext1,default,ext2` means ext1 will happens before all of the default extensions while ext2 will after them
ArrayList<T> extensionsResult = new ArrayList<>(activateExtensionsMap.size() + names.size());
for (String name : names) {
if (name.startsWith(REMOVE_VALUE_PREFIX)
|| namesSet.contains(REMOVE_VALUE_PREFIX + name)) {
continue;
}
if (DEFAULT_KEY.equals(name)) {
extensionsResult.addAll(activateExtensionsMap.values());
continue;
}
if (containsExtension(name)) {
extensionsResult.add(getExtension(name));
}
}
return extensionsResult;
} else {
// add extensions, will be sorted by its order
for (String name : names) {
if (name.startsWith(REMOVE_VALUE_PREFIX)
|| namesSet.contains(REMOVE_VALUE_PREFIX + name)) {
continue;
}
if (DEFAULT_KEY.equals(name)) {
continue;
}
if (containsExtension(name)) {
// 获取Activate扩展类实现,也是通过getExtension得到的
activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
}
}
return new ArrayList<>(activateExtensionsMap.values());
}
}
注意:如果URL的参数中传入了“-default”,则所有的默认@Activate都不会被激活,只有URL参数中指定的扩展点会被激活。如果传入了“—” 符号开头的扩展点名, 则该扩展点也不会被自动激活。
4、扩展点动态编译的实现
动态生成的自适应类只是字符串,需要通过编译才能得到真正的Class,配合动态编译器,灵活地在原始类基础上创建新的自适应类。Dubbo中有三种代码编译器,分别是JDK编译器、Javassist编译器和AdaptiveCompiler编译器。编译器类之间的关系如图:
Compiler接口上含有一个SPI注解,注解的默认值是@SPI(”javassist”),很明显,Javassist编译器将作为默认编译器。如果想改变默认编译器,则可以通过<dubbo:application compiler=“jdk” />标签进行配置。AdaptiveCompiler上面有@Adaptive注解,说明AdaptiveCompiler会固定为默认实现,用来管理其他Compiler,AdaptiveCompiler代码如下:
@Adaptive
public class AdaptiveCompiler implements Compiler, ScopeModelAware {
private FrameworkModel frameworkModel;
@Override
public void setFrameworkModel(FrameworkModel frameworkModel) {
this.frameworkModel = frameworkModel;
}
private static volatile String DEFAULT_COMPILER;
// 设置默认的编译器名称
// 在 ApplicationConfig 中被调用,也就是 Dubbo在启动时,会解析配置中的<dubbo:application compiler="jdk" />标签,获取设置的值,如果没有标签设置,贝U使用@SPI(Hjavassistn)中的设置,即3avassistCompilero
public static void setDefaultCompiler(String compiler) {
DEFAULT_COMPILER = compiler;
}
@Override
public Class<?> compile(Class<?> neighbor, String code, ClassLoader classLoader) {
Compiler compiler;
ExtensionLoader<Compiler> loader = frameworkModel.getExtensionLoader(Compiler.class);
String name = DEFAULT_COMPILER; // copy reference
if (name != null && name.length() > 0) {
compiler = loader.getExtension(name);
} else {
compiler = loader.getDefaultExtension();
}
// 通过ExtensionLoader获取对应的编译器扩展类实现,并调用真正的compile做编译
return compiler.compile(neighbor, code, classLoader);
}
}
4.1 Javassist动态代码编译
之前已经生成了代码字符串,因此在JavassistCompiler中,就是不断通过正则表达式匹配不同部位的代码,然后调用Javassist库中的API生成不同部位的代码,最后得到一个完整的Class对象。具体步骤如下:
- 初始化Javassist,设置默认参数,如设置当前的classpath
- 通过正则匹配出所有import的包,并使用Javassist添加import
- 通过正则匹配出所有extends的包,创建Class对象,并使用Javassist添加extends
- 通过正则匹配出所有implements包,并使用Javassist添加implements
- 通过正则匹配出类里面所有内容,即得到{}中的内容,再通过正则匹配出所有方法,并使用Javassist添加类方法
- 生成Class对象
以上步骤就是整个doCompile方法在JavassistCompiler中的实现,具体代码如下:
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(Class<?> neighbor, ClassLoader classLoader, String name, String source) throws Throwable {
CtClassBuilder builder = new CtClassBuilder();
builder.setClassName(name);
// process imported classes
Matcher matcher = IMPORT_PATTERN.matcher(source);
while (matcher.find()) {
builder.addImports(matcher.group(1).trim());
}
// process extended super class
matcher = EXTENDS_PATTERN.matcher(source);
if (matcher.find()) {
builder.setSuperClassName(matcher.group(1).trim());
}
// process implemented interfaces
matcher = IMPLEMENTS_PATTERN.matcher(source);
if (matcher.find()) {
String[] ifaces = matcher.group(1).trim().split("\\,");
Arrays.stream(ifaces).forEach(i -> builder.addInterface(i.trim()));
}
// process constructors, fields, methods
String body = source.substring(source.indexOf('{') + 1, source.length() - 1);
String[] methods = METHODS_PATTERN.split(body);
String className = ClassUtils.getSimpleClassName(name);
Arrays.stream(methods).map(String::trim).filter(m -> !m.isEmpty()).forEach(method -> {
if (method.startsWith(className)) {
builder.addConstructor("public " + method);
} else if (FIELD_PATTERN.matcher(method).matches()) {
builder.addField("private " + method);
} else {
builder.addMethod("public " + method);
}
});
// compile
CtClass cls = builder.build(classLoader);
ClassPool cp = cls.getClassPool();
if (classLoader == null) {
classLoader = cp.getClassLoader();
}
cp.insertClassPath(new LoaderClassPath(classLoader));
cp.insertClassPath(new DubboLoaderClassPath());
try {
return cp.toClass(cls, neighbor, classLoader, JavassistCompiler.class.getProtectionDomain());
} catch (Throwable t) {
if (!(t instanceof CannotCompileException)) {
return cp.toClass(cls, classLoader, JavassistCompiler.class.getProtectionDomain());
}
throw t;
}
}
}
4.2 JDK动态代码编译
JdkCompiler是Dubbo编译器的另一种实现,使用了JDK动态代码编译,整个动态编译过程可以简单地总结为:首先初始化一个JavaFileObject对象,并把代码字符串作为参数传入构造方法,然后调用JavaCompiler.CompilationTask方法编译出具体的类。JavaFileManager负责管理类文件的输入/输出位置。