本文主要针对使用springboot整合dubbo框架时使用zookeeper作为注册中心,在服务启动连接zookeeper产生的问题做一个详细的讲解。

        主要针对两个异常

(1)java.lang.IllegalStateException: java.lang.IllegalStateException: zookeeper not connected

(2)java.lang.IllegalStateException: failed to connect to zookeeper server

关于两个异常的详细信息见下方异常信息

1、异常详细信息

        (1) java.lang.IllegalStateException: java.lang.IllegalStateException: zookeeper not connected

java.lang.IllegalStateException: java.lang.IllegalStateException: zookeeper not connected
	at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.prepareEnvironment(DefaultApplicationDeployer.java:678) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.startConfigCenter(DefaultApplicationDeployer.java:261) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.initialize(DefaultApplicationDeployer.java:185) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.deploy.DefaultModuleDeployer.prepare(DefaultModuleDeployer.java:470) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.spring.context.DubboConfigApplicationListener.initDubboConfigBeans(DubboConfigApplicationListener.java:71) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.spring.context.DubboConfigApplicationListener.onApplicationEvent(DubboConfigApplicationListener.java:57) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.spring.context.DubboConfigApplicationListener.onApplicationEvent(DubboConfigApplicationListener.java:35) ~[dubbo-3.0.7.jar:3.0.7]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.registerListeners(AbstractApplicationContext.java:842) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:548) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:755) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:402) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1247) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1236) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at com.bao.Application.main(Application.java:11) [classes/:na]
Caused by: java.lang.IllegalStateException: zookeeper not connected
	at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init>(CuratorZookeeperClient.java:89) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter.createZookeeperClient(CuratorZookeeperTransporter.java:26) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.remoting.zookeeper.AbstractZookeeperTransporter.connect(AbstractZookeeperTransporter.java:69) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfiguration.<init>(ZookeeperDynamicConfiguration.java:63) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfigurationFactory.createDynamicConfiguration(ZookeeperDynamicConfigurationFactory.java:47) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory.lambda$getDynamicConfiguration$0(AbstractDynamicConfigurationFactory.java:39) ~[dubbo-3.0.7.jar:3.0.7]
	at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[na:1.8.0_131]
	at org.apache.dubbo.common.config.configcenter.AbstractDynamicConfigurationFactory.getDynamicConfiguration(AbstractDynamicConfigurationFactory.java:39) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.getDynamicConfiguration(DefaultApplicationDeployer.java:715) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.prepareEnvironment(DefaultApplicationDeployer.java:671) ~[dubbo-3.0.7.jar:3.0.7]
	... 20 common frames omitted
Caused by: java.lang.IllegalStateException: zookeeper not connected
	at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init>(CuratorZookeeperClient.java:85) ~[dubbo-3.0.7.jar:3.0.7]
	... 29 common frames omitted

 (2)java.lang.IllegalStateException: failed to connect to zookeeper server

java.lang.RuntimeException: Can not create registry service-discovery-registry://192.168.0.106:2181/org.apache.dubbo.registry.RegistryService?application=privoder_application&block-until-connected-wait=3&blockUntilConnectedWait=3&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=21212&qos.enable=false&registry=zookeeper&release=3.0.7&timeout=250000
	at org.apache.dubbo.registry.support.AbstractRegistryFactory.getRegistry(AbstractRegistryFactory.java:92) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.RegistryFactoryWrapper.getRegistry(RegistryFactoryWrapper.java:33) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.RegistryFactory$Adaptive.getRegistry(RegistryFactory$Adaptive.java) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.integration.RegistryProtocol.getRegistry(RegistryProtocol.java:393) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.integration.RegistryProtocol.export(RegistryProtocol.java:242) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper.export(ProtocolListenerWrapper.java:64) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.qos.protocol.QosProtocolWrapper.export(QosProtocolWrapper.java:74) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.rpc.cluster.filter.ProtocolFilterWrapper.export(ProtocolFilterWrapper.java:58) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.rpc.protocol.ProtocolSerializationWrapper.export(ProtocolSerializationWrapper.java:47) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.rpc.Protocol$Adaptive.export(Protocol$Adaptive.java) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.ServiceConfig.doExportUrl(ServiceConfig.java:641) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.ServiceConfig.exportRemote(ServiceConfig.java:619) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.ServiceConfig.exportUrl(ServiceConfig.java:578) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol(ServiceConfig.java:410) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.ServiceConfig.doExportUrls(ServiceConfig.java:396) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:361) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.ServiceConfig.export(ServiceConfig.java:233) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.deploy.DefaultModuleDeployer.exportServiceInternal(DefaultModuleDeployer.java:341) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.deploy.DefaultModuleDeployer.exportServices(DefaultModuleDeployer.java:313) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.deploy.DefaultModuleDeployer.start(DefaultModuleDeployer.java:145) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.spring.context.DubboDeployApplicationListener.onContextRefreshedEvent(DubboDeployApplicationListener.java:111) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.spring.context.DubboDeployApplicationListener.onApplicationEvent(DubboDeployApplicationListener.java:100) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.config.spring.context.DubboDeployApplicationListener.onApplicationEvent(DubboDeployApplicationListener.java:45) ~[dubbo-3.0.7.jar:3.0.7]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:404) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:361) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:898) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:755) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:402) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1247) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1236) [spring-boot-2.3.12.RELEASE.jar:2.3.12.RELEASE]
	at com.bao.Application.main(Application.java:11) [classes/:na]
Caused by: java.lang.IllegalStateException: Create zookeeper service discovery failed.
	at org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery.<init>(ZookeeperServiceDiscovery.java:77) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscoveryFactory.createDiscovery(ZookeeperServiceDiscoveryFactory.java:27) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory.lambda$getServiceDiscovery$0(AbstractServiceDiscoveryFactory.java:53) ~[dubbo-3.0.7.jar:3.0.7]
	at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[na:1.8.0_131]
	at org.apache.dubbo.registry.client.AbstractServiceDiscoveryFactory.getServiceDiscovery(AbstractServiceDiscoveryFactory.java:53) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.client.ServiceDiscoveryRegistry.getServiceDiscovery(ServiceDiscoveryRegistry.java:122) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.client.ServiceDiscoveryRegistry.createServiceDiscovery(ServiceDiscoveryRegistry.java:109) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.client.ServiceDiscoveryRegistry.<init>(ServiceDiscoveryRegistry.java:86) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.client.ServiceDiscoveryRegistryFactory.createRegistry(ServiceDiscoveryRegistryFactory.java:35) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.support.AbstractRegistryFactory.getRegistry(AbstractRegistryFactory.java:89) ~[dubbo-3.0.7.jar:3.0.7]
	... 37 common frames omitted
Caused by: java.lang.IllegalStateException: failed to connect to zookeeper server
	at org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.buildCuratorFramework(CuratorFrameworkUtils.java:75) ~[dubbo-3.0.7.jar:3.0.7]
	at org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery.<init>(ZookeeperServiceDiscovery.java:72) ~[dubbo-3.0.7.jar:3.0.7]
	... 46 common frames omitted

2、缘起

        前几天用springboot写了一个web项目,对外提供的是http请求接口,使用java程序调用不是很方便,于是想把它构建一个dubbo项目,方便服务间调用。在经过一系列的改造后,终于迎来了测试阶段。由于我是使用zookeeper作为注册中心,所以需要安装zookeeper(不会的可以自己查一下,网上教材很多)。由于嫌虚拟机麻烦,就直接在本机win10上启动了zookeeper,然后测试,程序服务注册和调用一切正常,No Problem!!!事情到这里本来是个美好的故事,然而……

        为了更接近真实的开发环境,我决定在程序调试完毕后,将zookeeper安装到linux虚拟机中,然而就是这个决定,改变了故事的结局——感觉遇到了一个天坑。

3、求知

        项目启动就报了第一个异常,本着有事问度娘的原则,第一个问题直接秒杀。简单说一下吧。

        根据异常定位到 package org.apache.dubbo.remoting.zookeeper.curator 包下的CuratorZookeeperClient类,其构造方法代码(截取部分,全部代码可自行查看)如下    

public class CuratorZookeeperClient extends AbstractZookeeperClient<CuratorZookeeperClient.NodeCacheListenerImpl, CuratorZookeeperClient.CuratorWatcherImpl> {
    private final CuratorFramework client;
    public CuratorZookeeperClient(URL url) {
        super(url);
        try {
            int timeout = url.getParameter(TIMEOUT_KEY, DEFAULT_CONNECTION_TIMEOUT_MS);
            int sessionExpireMs = url.getParameter(SESSION_KEY, DEFAULT_SESSION_TIMEOUT_MS);
            CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
                    .connectString(url.getBackupAddress())
                    .retryPolicy(new RetryNTimes(1, 1000))
                    .connectionTimeoutMs(timeout)
                    .sessionTimeoutMs(sessionExpireMs);
            String userInformation = url.getUserInformation();
            if (StringUtils.isNotEmpty(userInformation)) {
                builder = builder.authorization("digest", userInformation.getBytes());
            }
            client = builder.build();
            client.getConnectionStateListenable().addListener(new CuratorConnectionStateListener(url));
            client.start();
            //第一个异常出现在这里
            boolean connected = client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS);
            if (!connected) {
                throw new IllegalStateException("zookeeper not connected");
            }
        } catch (Exception e) {
            close();
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

}

        解释一下这个CuratorZookeeperClient,它是对原生zookeeper客户端的一个封装,就好比mybatis是对原生JDBC的封装一样。CuratorZookeeperClient里面有个CuratorFramework类型的属性client,在这个属性中真正封装了一个zookeeper客户端。CuratorZookeeperClient的构造方法中传了一个URL对象,这个URL对象中封装了创建zookeeper客户端需要的参数信息,如下

zookeeper://192.168.0.106:2181/org.apache.dubbo.config.ConfigCenterConfig?block-until-connected-wait=3&blockUntilConnectedWait=3&check=true&config-file=dubbo.properties&group=dubbo&highest-priority=false&namespace=dubbo&timeout=30000

 这就是一个URL地址,类似于http的get请求,“?”前面是协议和zookeeper主机地址,后面是参数。然后将参数提取出来,传到需要的方法中。而这些参数则是通过配置文件application.yml或application.properties文件配置的,如图

94265e3110c6472eb509f750a114e701.png

        这里的参数会自动解析到URL中,当然不是所有的参数都会封装到URL中,只是封装一部分,如果没有定义相应参数,则会采用默认值。

public class CuratorZookeeperClient extends AbstractZookeeperClient<CuratorZookeeperClient.NodeCacheListenerImpl, CuratorZookeeperClient.CuratorWatcherImpl> {
    private final CuratorFramework client;
    public CuratorZookeeperClient(URL url) {
        super(url);
        try {
            int timeout = url.getParameter(TIMEOUT_KEY, DEFAULT_CONNECTION_TIMEOUT_MS);
            int sessionExpireMs = url.getParameter(SESSION_KEY, DEFAULT_SESSION_TIMEOUT_MS);
            CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
                    .connectString(url.getBackupAddress())
                    .retryPolicy(new RetryNTimes(1, 1000))
                    .connectionTimeoutMs(timeout)
                    .sessionTimeoutMs(sessionExpireMs);
            String userInformation = url.getUserInformation();
            if (StringUtils.isNotEmpty(userInformation)) {
                builder = builder.authorization("digest", userInformation.getBytes());
            }
            client = builder.build();
            client.getConnectionStateListenable().addListener(new CuratorConnectionStateListener(url));
            client.start();
            //第一个异常出现在这里
            boolean connected = client.blockUntilConnected(timeout, TimeUnit.MILLISECONDS);
            if (!connected) {
                throw new IllegalStateException("zookeeper not connected");
            }
        } catch (Exception e) {
            close();
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

}

        第一个异常出现的位置见代码注释,根据网友的解答,这里的异常是因为等待连接超时引起的。这里的timeout默认是30秒,就是说如果30秒内没有连接成功,就会报错。通常情况下本机的zookeeper连接可以在30秒内完成,但是虚拟机那边连接就贼慢。

到这里第一个异常就解决了,只需要配置timeout参数大一些即可,如图所示。

b621834d87f94e59933ed9ed983bf2ed.png

4、入坑

        正当我微微一笑,心想不过如此,so easy时,转身掉进了一个天坑。

        好家伙,知道原因后我这暴脾气直接给timeout干到250秒,等待项目起飞时,第二个异常来了。此时的我根本不知道事情的严重性,依然稳如一条老狗,默默打开百度……n分钟后,我特么傻了,整个网上都没有对这个异常的解决的帖子(反正我是没找到)。第二个异常信息里面有三个异常,我都搜了一遍,还是没找到。我真是醉了,难道这么多人都没遇到这个问题吗?然后怎么办呢,只能根据控制台信息排查。通过第二个异常的倒数第三行,我来到了这个类,如下(删除了部分源码,只留了报错的部分)

package org.apache.dubbo.registry.zookeeper.util;

public abstract class CuratorFrameworkUtils {

    public static CuratorFramework buildCuratorFramework(URL connectionURL) throws Exception {
        CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
            .connectString(connectionURL.getBackupAddress())
            .retryPolicy(buildRetryPolicy(connectionURL))
            .build();
        curatorFramework.start();
        //这段代码是不是似曾相识?
        curatorFramework.blockUntilConnected(BLOCK_UNTIL_CONNECTED_WAIT.getParameterValue(connectionURL),
            BLOCK_UNTIL_CONNECTED_UNIT.getParameterValue(connectionURL));

        if (!curatorFramework.getState().equals(CuratorFrameworkState.STARTED)) {
            throw new IllegalStateException("zookeeper client initialization failed");
        }

        if (!curatorFramework.getZookeeperClient().isConnected()) {
            //这里抛异常了
            throw new IllegalStateException("failed to connect to zookeeper server");
        }
        return curatorFramework;
    }
}

        我一看这个代码,似曾相识啊,好家伙,这不是跟上一个异常一样吗?设置一下超时时间就行了吗?感觉不过如此,事实证明还是太年轻了啊。

        通过源码中这个方法

curatorFramework.blockUntilConnected(BLOCK_UNTIL_CONNECTED_WAIT.getParameterValue(connectionURL),
            BLOCK_UNTIL_CONNECTED_UNIT.getParameterValue(connectionURL));

        我找到了这个枚举类。 

package org.apache.dubbo.registry.zookeeper.util;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.registry.client.ServiceInstance;

import org.apache.curator.framework.CuratorFramework;

import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * The enumeration for the parameters  of {@link CuratorFramework}
 *
 * @see CuratorFramework
 * @since 2.7.5
 */
public enum CuratorFrameworkParams {

    BLOCK_UNTIL_CONNECTED_WAIT("blockUntilConnectedWait", 10, Integer::valueOf),

    /**
     * The unit of time related to blocking on connection to Zookeeper.
     */
    BLOCK_UNTIL_CONNECTED_UNIT("blockUntilConnectedUnit", TimeUnit.SECONDS, TimeUnit::valueOf),

    ;

    private final String name;

    private final Object defaultValue;

    private final Function<String, Object> converter;

    <T> CuratorFrameworkParams(String name, T defaultValue, Function<String, T> converter) {
        this.name = name;
        this.defaultValue = defaultValue;
        this.converter = (Function<String, Object>) converter;
    }

    /**
     * Get the parameter value from the specified {@link URL}
     *
     * @param url the Dubbo registry {@link URL}
     * @param <T> the type of value
     * @return the parameter value if present, or return <code>null</code>
     */
    public <T> T getParameterValue(URL url) {
        String param = url.getParameter(name);
        Object value = param != null ? converter.apply(param) : defaultValue;
        return (T) value;
    }
}

发现这个BLOCK_UNTIL_CONNECTED_WAIT对象中设置了一个默认值10,也就是说10秒内连接不上就会报异常。好家伙,前面是30都不行,这里居然给个10。

 为此我还把这段代码拿出来亲自测试了一下,测试代码如下

import org.apache.curator.CuratorZookeeperClient;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;

public class TestCurator {
    public static void main(String[] args) throws Exception {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
         CuratorFramework client = CuratorFrameworkFactory.builder()
         .connectString("192.168.0.106:2181")
//         .connectString("localhost:2181")
         .sessionTimeoutMs(5000) // 会话超时时间
         .connectionTimeoutMs(5000) // 连接超时时间
         .retryPolicy(retryPolicy)
         .namespace("base")
         .build();
         client.start();
        long l = System.currentTimeMillis();
        //这里不传参数表示无限制等待
        client.blockUntilConnected();
        long l1 = System.currentTimeMillis();
        long l2 = l1 - l;
        //输出等待连接毫秒数
        System.out.println(l2);
        CuratorZookeeperClient zookeeperClient = client.getZookeeperClient();
        boolean connected = zookeeperClient.isConnected();
        System.out.println(connected);

    }
}

经过测试,快则需要30+秒,慢则需要60+秒,有兴趣的可以自己测一下。

        不过连接本机zookeeper居然啥事儿没有,看来本机还是快啊。根据经验,参数配置在配置文件中,只需输入参数名就会有提示。

        没想到从这里就是噩梦的开始……

        根据枚举对象中参数名称blockUntilConnectedWait,准备去配置文件中设置该属性的值。正当我输入该变量名称时,居然没有提示,没有提示意味着没有该变量属性。到这里,问题看上去已经解决了90%,只要找到变量设置一下值就行了。但是,其实就解决了10%,问题就出在这个变量去哪里设置?我找了好久也没看到这个变量的名字,然后默默打开了百度……结果啥也没有。这里问题就严重了,这得去源码里面找啊。最开始肯定去看dubbo的自动配置类啊,如下图,结果dubbo有两个自动配置的包。

eb16389e8d4e468abca4c596bc8d1298.png

        我一眼就看到了第一个,忽略了第二个(不知道为啥有两个,一个不好吗),结果第一个包里没找到属性配置类(其实在第二个包里)。我反复看了几遍,这个自动配置类跟之前看过的其他组件的自动配置类套路咋不一样,找了半天没找到,我就以为URL的参数绑定肯定是在dubbo启动的时候通过spring完成的。肯定是spring封装好的URL直接给dubbo,然后dubbo给zookeeper(回头想想,我特么真佩服我的脑洞)。

        然后我就从@EnableDubbo注解开始,一步一步调试dubbo。就想找到那个URL组装的地方,看看blockUntilConnectedWait属性怎么搞进去。卧槽了,真的,我特么从0点一直调试到4点多,就为了找那个URL组装的地方。结果没找到,我真的裂开,要吐了。

        终于,我不知怎么看到了第二个自动配置的jar包,我进去一看,瞬间懂了,那个属性配置类就在这个包里面,参数是通过配置类自动映射绑定上去的,跟我之前想的一样,只不过没看到这个包。然后我把所有的属性配置类都看了一遍,还是没找到blockUntilConnectedWait这个属性。给我气的,我当时直接想去源码中把BLOCK_UNTIL_CONNECTED_WAIT对象的默认值给改了。

        然后以为是idea配置文件提示有问题,强行设置blockUntilConnectedWait属性,但是不起作用。一看都特么快5点了,放弃了……

        早上八点就起来了,吃完早饭坐在电脑前一遍一遍的看属性配置类的属性。直到我看到这个parameters参数

791872f21530436f87f26cd8d445f655.png

        真是山重水复疑无路,柳暗花明又一村啊,我赶紧通过这个新的参数试了一下。

a3c7aaeb00a24627a32662d0081bb0e9.png

                终于,设置成功了,这谁能想的到,事实证明,还是得看源码。至此,项目终于可以起飞了。

4、结语

        b657f36e7ce841ef862f36860cf73771.png

 

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐