SpringBoot2.x+Dubbo2.7.3+Redis实现分布式开发(为坑比公司省个服务器)

4 篇文章 0 订阅
3 篇文章 0 订阅

SpringBoot2.x+Dubbo2.7.3+Redis实现分布式开发


这个这个由于公司经费不够,没有放Zookeeper的服务器,所以这次研究一下这个冷门。使用Redis作为注册中心来实现分布式开发。

1.dependency配置

有关Dubbo 的配置

<dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-registry-redis</artifactId>
            <version>2.7.3</version>
        </dependency>
2.applications.properties

因为redis的0库和1库都被占用了,所以这里使用2库。

#dubbo.registry.address格式:redis://username:password@ip:port?db.index:指定数据库,&...一些别的参数
dubbo.application.name=dubbo-redis-server
dubbo.scan.base-packages=com.ld.service
dubbo.registry.id=dubbo-registry-test
dubbo.registry.address=redis://username:password@127.0.0.1:6379?db.index=2
dubbo.metadata-report.address=redis://username:password@127.0.0.1:6379?db.index=2
dubbo.provider.timeout=15000
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
3.demo

实现就和zookeeper作为注册中心的使用一样了。
interface:

public interface TestService {
    public String test();
}

impl:

import com.ld.service.TestService;
import org.apache.dubbo.config.annotation.Service;

@Service(version = "1.0")
public class TestServiceImpl implements TestService {
    @Override
    public String test() {
        return "hello world.";
    }
}

test:

import com.ld.service.TestService;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.junit.jupiter.api.Test;

public class DubboTest {

    @Test
    public void test(){
        ApplicationConfig application = new ApplicationConfig();
        application.setName("yyy");

// 连接注册中心配置
        RegistryConfig registry = new RegistryConfig();
//        registry.setAddress("127.0.0.1:2182");
        registry.setAddress("redis://username:password@127.0.0.1:6379?db.index=2");
//        registry.setUsername("aaa");
//        registry.setPassword("bbb");

// 注意:ReferenceConfig为重对象,内部封装了与注册中心的连接,以及与服务提供方的连接

// 引用远程服务
        ReferenceConfig<TestService> reference = new ReferenceConfig<>(); // 此实例很重,封装了与注册中心的连接以及与提供者的连接,请自行缓存,否则可能造成内存和连接泄漏
        reference.setApplication(application);
        reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
        reference.setInterface(TestService.class);
        reference.setVersion("1.0");

        TestService testService = reference.get();
        String aaa = testService.test();
        System.out.println(aaa);
    }
}
4. 遇到的坑比问题

问题1:dubbo.registry.address和dubbo.metadata-report.address这两个的值不知道怎么写了?
因为官网上也没有给个比较全的地址格式,所以只能靠自己琢磨了。因为它是使用org.apache.dubbo.common.URL来解析url 的,所以我们就去看看这个类,然后找到类这段代码:

public static URL valueOf(String url) {
        if (url != null && (url = url.trim()).length() != 0) {
            String protocol = null;
            String username = null;
            String password = null;
            String host = null;
            int port = 0;
            String path = null;
            Map<String, String> parameters = null;
            int i = url.indexOf("?");
            if (i >= 0) {
                String[] parts = url.substring(i + 1).split("&");
                parameters = new HashMap();
                String[] var10 = parts;
                int var11 = parts.length;

                for(int var12 = 0; var12 < var11; ++var12) {
                    String part = var10[var12];
                    part = part.trim();
                    if (part.length() > 0) {
                        int j = part.indexOf(61);
                        if (j >= 0) {
                            parameters.put(part.substring(0, j), part.substring(j + 1));
                        } else {
                            parameters.put(part, part);
                        }
                    }
                }

                url = url.substring(0, i);
            }

            i = url.indexOf("://");
            if (i >= 0) {
                if (i == 0) {
                    throw new IllegalStateException("url missing protocol: \"" + url + "\"");
                }

                protocol = url.substring(0, i);
                url = url.substring(i + 3);
            } else {
                i = url.indexOf(":/");
                if (i >= 0) {
                    if (i == 0) {
                        throw new IllegalStateException("url missing protocol: \"" + url + "\"");
                    }

                    protocol = url.substring(0, i);
                    url = url.substring(i + 1);
                }
            }

            i = url.indexOf("/");
            if (i >= 0) {
                path = url.substring(i + 1);
                url = url.substring(0, i);
            }

            i = url.lastIndexOf("@");
            if (i >= 0) {
                username = url.substring(0, i);
                int j = username.indexOf(":");
                if (j >= 0) {
                    password = username.substring(j + 1);
                    username = username.substring(0, j);
                }

                url = url.substring(i + 1);
            }

            i = url.lastIndexOf(":");
            if (i >= 0 && i < url.length() - 1 && url.lastIndexOf("%") <= i) {
                port = Integer.parseInt(url.substring(i + 1));
                url = url.substring(0, i);
            }

            if (url.length() > 0) {
                host = url;
            }

            return new URL(protocol, username, password, host, port, path, parameters);
        } else {
            throw new IllegalArgumentException("url == null");
        }
    }

代码很长,但是是主要的,所以我们得好好研究一下,最后琢磨出来一个地址:redis://username:password@host:port,虽然不知道能不能用,但是最起码有个地址。
问题2:redis只有密码没有用户名,不写用户用就报错Invalid url, password without?
如果redis没有密码,那配置和zookeeper一样,但是有了密码就不行了,因为redis访问要密码啊,那就开始配置密码,配置完成之后会发现启动报错了,

IllegalArgumentException:Invalid url, password without username!

因为它解析url使用的是URL类,
去查看源码发现,在URL类中有这么个判断
在这里插入图片描述
如果设置可密码,肯定有用户名非空的校验,那我们就自己瞎写i一个用户名,然后竟然就给通过了。。。
问题3: 因为公司redis的0库已经再用了,所以这个dubbo服务我想注册到别的库里面,但是参数如何配置?
查看redis注册类org.apache.dubbo.registry.redis.RedisRegistry。进去就看到了这么个构造函数:

public RedisRegistry(URL url) {
        super(url);
        if (url.isAnyHost()) {
            throw new IllegalStateException("registry address == null");
        } else {
            GenericObjectPoolConfig config = new GenericObjectPoolConfig();
            。。。
                String address;
                String host;
                int port;
                for(Iterator var6 = addresses.iterator(); var6.hasNext(); this.jedisPools.put(address, new JedisPool(config, host, port, url.getParameter("timeout", 1000), StringUtils.isEmpty(url.getPassword()) ? null : url.getPassword(), url.getParameter("db.index", 0)))) {
                    address = (String)var6.next();
                    int i = address.indexOf(58);
                    if (i > 0) {
                        host = address.substring(0, i);
                        port = Integer.parseInt(address.substring(i + 1));
                    } else {
                        host = address;
                        port = 6379;
                    }
                }

                this.reconnectPeriod = url.getParameter("reconnect.period", 3000);
                String group = url.getParameter("group", "dubbo");
                if (!group.startsWith("/")) {
                    group = "/" + group;
                }

                if (!group.endsWith("/")) {
                    group = group + "/";
                }

               。。。
            }
        }
    }

发现这里都是配置一些redis的参数,找到了这么一句

 url.getParameter("db.index", 0)

感觉有可能是这个,然后就修改了一下地址:redis://username:password@host:port?db.index=2,然后重新启动。发现成功写到2库里。

问题4: dubbo2.7以后增加了元数据中心,所以我也装模作样的配置了一下:dubbo.metadata-report.address=redis://username:password@host:port?db.index=2。启动后发现,然并卵啊,没有在2库中找到相关的元数据。竟然在默认的0库找到了
去查看解析这个配置的源码,找到这个构造函数:
在这里插入图片描述
发现它竟然没有主动设置redis库,那肯定就是使用了默认0库了,这还能忍,直接废弃了,按照相同的目录在自己的项目里新建一个相同的类,然后把代码复制过来。
在这里插入图片描述
相同的路径,相同的名字来个类。然后把代码复制过来。
把设置redis的地方修改下:

public RedisMetadataReport(URL url) {
        super(url);
        this.timeout = url.getParameter("timeout", 1000);
        this.password = url.getPassword();
        if (url.getParameter("cluster", false)) {
            this.jedisClusterNodes = new HashSet();
            List<URL> urls = url.getBackupUrls();
            Iterator var3 = urls.iterator();

            while(var3.hasNext()) {
                URL tmpUrl = (URL)var3.next();
                this.jedisClusterNodes.add(new HostAndPort(tmpUrl.getHost(), tmpUrl.getPort()));
            }
        } else {
            this.pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort(), this.timeout, StringUtils.isEmpty(url.getPassword()) ? null : url.getPassword(), url.getParameter("db.index", 0));
//            this.pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort(), this.timeout, url.getPassword());
        }

注释掉之前的。

this.pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort(), this.timeout, url.getPassword());

新加上指定数据库的JedisPool构造函数:

this.pool = new JedisPool(new JedisPoolConfig(), url.getHost(), url.getPort(), this.timeout, StringUtils.isEmpty(url.getPassword()) ? null : url.getPassword(), url.getParameter("db.index", 0));

然后启动,问题解决。。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值