dubbo 动态编译生成类源码

如果文章对您有帮助,请给个点赞或者收藏,谢谢!

问题

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点

  1. 标注在方法上,就是用于在动态生成的方法中添加自动检查URL中对应参数是否存在的代码,如果不存在则抛出异常.
  2. 标注在类上,就是按照对应接口的spi文件中设置的adaptive=xxx作为具体实现,尤其决定真正应该调用的扩展类.

待补充

还有部分通过javaassist直接生成字节码加载的,这部分之后补充.

猜你喜欢

转载自blog.csdn.net/weixin_46080554/article/details/125192736
今日推荐