GitHub user mz0113 edited a discussion: [General][Java SDK (Component)] 
serviceConfig.getRegistries() return null when destroy service , casuing 
NullPointerExcetpion

### Pre-check

- [X] I am sure that all the content I provide is in English.


### Apache Dubbo Component

Java SDK (apache/dubbo)

### Details

`    private void doExport(Instance interfaceInstance, List<String> registries, 
BridgelessItem bridgelessItem)
            throws ClassNotFoundException, ExecutionException, 
InterruptedException, TimeoutException {
        ClassLoader interfaceClassLoader = bridgelessItem.getClassLoader();
        Map<String, String> interfaceInstanceMetadata = 
interfaceInstance.getMetadata();

        List<RegistryConfig> registryConfigs = getRegistryConfigs(registries);
        if (registryConfigs.size() == 0) {
            log.info("no matched zk,skip 
export,bridgelessItem:{},interfaceInstance:{}", bridgelessItem,
                    interfaceInstance);
            return;
        }
        //protocol
        ProtocolConfig protocolConfig = getProtocolConfig();
        //service
        String anInterface = interfaceInstanceMetadata.get(Constants.INTERFACE);
        ServiceConfig serviceConfig;
        if (MobileAdapterService.class.getCanonicalName().equals(anInterface)) {
            serviceConfig = new MGSAdapterServiceConfig();
        } else {
            serviceConfig = new ServiceConfig();
        }
        serviceConfig.setRegistries(registryConfigs);
        serviceConfig.setProtocol(protocolConfig);
        serviceConfig.setInterface(anInterface);
        String version = interfaceInstanceMetadata.get(Constants.VERSION);
        serviceConfig.setVersion(version);

        // 设置权重,小于0的话说明未配置权重,使用全局默认权重
        Integer weight = bridgelessItem.getBridgelessConfig().getWeight();
        if (weight >= 0) {
            serviceConfig.setWeight(weight);
        }

        //解决dubbo3.0.10的tri协议存在group被默认填充tri的问题
        String group = interfaceInstanceMetadata.get(Constants.GROUP);
        if (Constants.PROTOCOL_TRI.equals(group)) {
            serviceConfig.setGroup("");
        } else {
            serviceConfig.setGroup(group);
        }

        String generic = interfaceInstanceMetadata.get(Constants.GENERIC);
        if (StringUtils.isNotBlank(generic)) {
            serviceConfig.setGeneric(generic);
        }

        serviceConfig.setInterfaceClassLoader(interfaceClassLoader);
        serviceConfig.setRef(DubboReferenceHelper.getRef(interfaceInstance, 
bridgelessItem, metaRPCHelper));

        //tag会被dubbo.provider.tag覆盖,所以需要手动fresh()+setProviderConfig
        String timeout = interfaceInstanceMetadata.get(Constants.TIMEOUT);
        if (StringUtils.isNotBlank(timeout)) {
            serviceConfig.setTimeout(Integer.parseInt(timeout));
        }
        serviceConfig.refresh();

//        solveThreadPoolConfig(serviceConfig);
        // 解决只新增方法无效问题
        serviceConfig.setProxy("jdk");
        serviceConfig.setTag("");
        ProviderConfig providerConfig = getProviderConfig(timeout);
        serviceConfig.setProvider(providerConfig);

        // 注册服务
        serviceConfig.export();
        bridgelessItem.getServiceConfigList().add(serviceConfig);
        log.info("export 
success,appName:{},env:{},link:{},interface:{},version:{},group:{},serviceConfig:{}",
                bridgelessItem.getBridgelessConfig().getAppName(),
                bridgelessItem.getBridgelessConfig().getEnv(),
                bridgelessItem.getBridgelessConfig().getLink(), anInterface, 
version, group,
                serviceConfig);
    }










        public void destroySync(BridgelessConfig bridgelessConfig, boolean 
retainClassLoader)
            throws IOException, InterruptedException {
        DubboProtocol dubboProtocol = 
DubboProtocol.getDubboProtocol(ApplicationModel.defaultModel());
        BridgelessItem bridgelessItem = 
bridgelessItemCache.getLocalCache(bridgelessConfig.getAppName(),
                bridgelessConfig.getEnv(), bridgelessConfig.getLink());
        List<ServiceConfig> serviceConfigList = 
bridgelessItem.getServiceConfigList();
        int toUnExportedSize = serviceConfigList.size();
        int countDownSize = 0;
        for (ServiceConfig serviceConfig : serviceConfigList) {
            int size = serviceConfig.getRegistries().size();
            countDownSize += size;
        }
        CountDownLatch countDownLatch = new CountDownLatch(countDownSize);

        //registry -> registerProviderUrl
        HashMap<Registry, URL> toRegistryMap = new HashMap<>();

        for (ServiceConfig serviceConfig : serviceConfigList) {
            try {
                destroyRegistry(toRegistryMap, serviceConfig);
            } catch (Exception e) {
                LogUtil.error(log, "error when destroyRegistry:{}", () -> e);
            }
        }
        //留出一点时间,用于受理C端残余的流量(zk异步通知有时延)
        TimeUnit.MILLISECONDS.sleep(unRegistryAhead);
        for (ServiceConfig serviceConfig : serviceConfigList) {
            try {
                serviceConfig.unexport();
            } catch (Exception e) {
                LogUtil.error(log, "exception when 
unExport,serviceConfig:{},e:", () -> serviceConfig, () -> e);
                //防止死锁
                countDownLatch.countDown();
            }

            ModuleModel scopeModel = serviceConfig.getScopeModel();
            String path = serviceConfig.getPath();
            if (StringUtils.isBlank(path)) {
                path = serviceConfig.getInterface();
            }
            String version = serviceConfig.getVersion();
            String group = serviceConfig.getGroup();
            String serviceKey = BaseServiceMetadata.buildServiceKey(path, 
version, group);
            //同步unexport走完后才放入,让异步unexport后去countDown
            BridgelessItemCache.setCountDownLatch2Cache(scopeModel, serviceKey, 
countDownLatch);
        }
        //countdown的替代方案
        //        TimeUnit.MILLISECONDS.sleep(unExportDelay);
        LogUtil.debug(log, "before await");
        countDownLatch.await(unExportDelay, TimeUnit.MILLISECONDS);
        LogUtil.debug(log, "exporters:{}", () -> 
dubboProtocol.getExporters().size());

        if (retainClassLoader) {//保留classLoader,以便于下次复用
            bridgelessItem.setBridgelessConfig(null);
            bridgelessItem.getServiceConfigList().clear();
        } else {
            Set<Class> interfaceSet = 
serviceConfigList.stream().map(serviceConfig -> 
serviceConfig.getInterfaceClass())
                    .collect(Collectors.toSet());
            bridgelessItemCache.deleteLocalCache(bridgelessConfig.getAppName(), 
bridgelessConfig.getEnv(),
                    bridgelessConfig.getLink());
            //dubbo中unExport时没有删除缓存,这里补删,否则由于dubbo缓存中不考虑classLoader隔离导致调用失败
            pojoUtilsExpandUtil.deleteDubboPojoUtilCache(interfaceSet, 
bridgelessItem.getClassLoader());
        }

        //如果原本需要unExport的服务个数大于0,则输出一下日志
        if (toUnExportedSize > 0) {
            log.info("unExport success,appName:{},env:{},link:{}", 
bridgelessConfig.getAppName(),
                    bridgelessConfig.getEnv(), bridgeLink);
        }
    }`

### Code of Conduct

- [X] I agree to follow this project's [Code of 
Conduct](https://www.apache.org/foundation/policies/conduct)


GitHub link: https://github.com/apache/dubbo/discussions/15502

----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to: 
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to