如果文章对您有帮助,请给个点赞或者收藏,谢谢!
问题
dubbo会很很多动态生成的类,在我们debug的时候非常不方便. 我对源码添加了一些代码,可以对动态类生成相应的源码.
代码
我们找到dubbo源码中的ExtensionLoader
类,然后找到createAdaptiveExtensionClass
方法,添加下面有注释的代码.
private Class<?> createAdaptiveExtensionClass() {
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
// 添加生成动态源码类的入口
genClassSourceFile(code);
return compiler.compile(code, classLoader);
}
/**
* 为动态生成的类创建相应的源码文件(.java),便于debug
*
* @param code 动态代码
*/
private void genClassSourceFile(String code) {
// 将动态代码放入正确的项目路径中
String projectRootPath = System.getProperties().getProperty("user.dir") + File.separator;
HashMap<String, String> pathMap = new HashMap<String, String>();
// fixme 可能不全 如果缺少对应包的目录,添加到这里
pathMap.put("com.alibaba.dubbo.rpc.cluster", "dubbo-cluster\\src\\main\\java\\com\\alibaba\\dubbo\\rpc\\cluster");
pathMap.put("com.alibaba.dubbo.rpc", "dubbo-rpc\\dubbo-rpc-api\\src\\main\\java\\com\\alibaba\\dubbo\\rpc");
pathMap.put("com.alibaba.dubbo.registry", "dubbo-registry\\dubbo-registry-api\\src\\main\\java\\com\\alibaba\\dubbo\\registry");
pathMap.put("com.alibaba.dubbo.remoting", "dubbo-remoting\\dubbo-remoting-api\\src\\main\\java\\com\\alibaba\\dubbo\\remoting");
pathMap.put("com.alibaba.dubbo.common.threadpool", "dubbo-common\\src\\main\\java\\com\\alibaba\\dubbo\\common\\threadpool");
// 添加idea项目根目录前缀
for (Map.Entry<String, String> entry : pathMap.entrySet()) {
entry.setValue(projectRootPath + entry.getValue());
}
// 查询是否能找到对应包的目录
String writeDir = pathMap.get(type.getPackage().getName());
if (null == writeDir) {
logger.error("not found interface: " + type.getPackage().getName());
return;
}
String className = code.substring(code.indexOf("public class") + 12, code.indexOf("implements")).trim();
File file = new File(writeDir + File.separator + className + ".java");
try {
boolean newFile = file.createNewFile();
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(code);
fileWriter.flush();
fileWriter.close();
} catch (Exception e) {
logger.error(e.getMessage() + "; " + file.getAbsolutePath());
}
}
效果截图
处于方便,贴上自动生成的源码.
接口
@SPI("dubbo")
public interface Protocol {
int getDefaultPort();
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
void destroy();
}
动态生成的Adaptive 源码.
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException(
"method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException(
"method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1)
throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) {
throw new IllegalArgumentException("url == null");
}
com.alibaba.dubbo.common.URL url = arg1;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null) {
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
}
com.alibaba.dubbo.rpc.Protocol extension =
(com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
.getExtension(extName);
return extension.refer(arg0, arg1);
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null) {
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
}
if (arg0.getUrl() == null) {
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
}
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null) {
throw new IllegalStateException(
"Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
}
com.alibaba.dubbo.rpc.Protocol extension =
(com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
.getExtension(extName);
return extension.export(arg0);
}
}
dubbo的@Adaptive
注解的作用有2点
- 标注在方法上,就是用于在动态生成的方法中添加自动检查URL中对应参数是否存在的代码,如果不存在则抛出异常.
- 标注在类上,就是按照对应接口的spi文件中设置的
adaptive=xxx
作为具体实现,尤其决定真正应该调用的扩展类.
待补充
还有部分通过javaassist直接生成字节码加载的,这部分之后补充.