dubbo ReferenceConfigCache缓存导致获取的服务是同一个

1.业务背景

有2个不同区域的zookeeper,工程需要调用一个zookeeper的服务,然后再调用另外一个zookeeper,这2个服务的名字是一样的,但因为在不同的注册中心,所以不会冲突。

2.设计方案

消费者端通过动态设置ReferenceConfig的方式来获取不同区域的zookeeper中的服务

3. 我写了一个DubboUtils来根据参数动态的获取服务,为了性能我还加入了ReferenceConfigCache 来作为缓存,代码如下

public class DubboUtils {
	public static RouterService getInvokeRouterService(String applicationName, String registryId) {

		ApplicationConfig application = new ApplicationConfig();
		application.setName(applicationName);

		RegistryConfig registry = new RegistryConfig();
		registry.setAddress(registryId);//这里就是动态的设置zookeeper的id
		registry.setProtocol("zookeeper");

		ReferenceConfig referenceConfig = new ReferenceConfig<>();
		referenceConfig.setApplication(application);
		referenceConfig.setRegistry(registry);
		referenceConfig.setInterface(RouterService.class);
		ReferenceConfigCache cache = ReferenceConfigCache.getCache();
		return cache.get(referenceConfig);
	}

}

4.我写了一个测试类,先调用 zookeeper1中的服务,然后再调用zookeeper2中的服务,代码如下

	public void testRouter() {

		RouterService invokeRouterService = DubboUtils.getInvokeRouterService("router1", "zookeeper://localhost:2181");
		invokeRouterService.testMethod();

		RouterService invokeRouterService2 = DubboUtils.getInvokeRouterService("router2", "zookeeper://localhost:2182");
		invokeRouterService2.testMethod();
	}

5.结果却发现zookeeper1中的服务被调用了2次,而zookpeer2中的服务没有被调用。我网上查了一下,没有结果,根据我多年的开发经验,问题一定是出在ReferenceConfigCache这个缓存上,于是我点开了cache.get(referenceConfig)这个方法,代码如下

    @SuppressWarnings("unchecked")
    public  T get(ReferenceConfig referenceConfig) {
        String key = generator.generateKey(referenceConfig);

        ReferenceConfig config = cache.get(key);
        if (config != null) {
            return (T) config.get();
        }

        cache.putIfAbsent(key, referenceConfig);
        config = cache.get(key);
        return (T) config.get();
    }

6.看到String key = generator.generateKey(referenceConfig);这句话,会根据ReferenceConfig来查找缓存对象,于是再点击进去,代码如下

public static final KeyGenerator DEFAULT_KEY_GENERATOR = new KeyGenerator() {
        @Override
        public String generateKey(ReferenceConfig referenceConfig) {
            String iName = referenceConfig.getInterface();
            if (StringUtils.isBlank(iName)) {
                Class clazz = referenceConfig.getInterfaceClass();
                iName = clazz.getName();
            }
            if (StringUtils.isBlank(iName)) {
                throw new IllegalArgumentException("No interface info in ReferenceConfig" + referenceConfig);
            }

            StringBuilder ret = new StringBuilder();
            if (!StringUtils.isBlank(referenceConfig.getGroup())) {
                ret.append(referenceConfig.getGroup()).append("/");
            }
            ret.append(iName);
            if (!StringUtils.isBlank(referenceConfig.getVersion())) {
                ret.append(":").append(referenceConfig.getVersion());
            }
            return ret.toString();
        }
    };

7.果然, 这个key的生成规则只会根据ReferenceConfig中的Group和Version这2个字段,而我在Registry中设置的Address根本没有作用,所以造成了我上面说的问题。

8.看了源代码之后,解决方案就很简单了,只要给2个服务对象上加上不同的Group属性就可以了,这样缓存在获取key的时候就能根据这个字段来返回不同的对象。所以大家以后遇到问题还是要多看源代码。

 

你可能感兴趣的:(dubbo,dubbo,dubbo缓存)