博客中代码地址:https://github.com/farliu/farpc.git
dubbo架构

在上两章中,我们基于zookeeper实现了dubbo的注册中心。本章是作为服务治理的番外篇讲述,对注册中心的另一种实现方案探讨。也为接下来讲述SPI做好铺垫。

那么本章是基于redis作为存储中间件,实现服务治理,也就是图片中的第1,2,3步,思路跟zookeeper实现方式一致,存储结构也大致相同。使用redis的list类型。想详细了解redis的,请跳转至redis妙用,这里讲述了redis的各种应用场景,以及将遇到的坑。

项目结构介绍

项目结构
本节涉及博客中代码的module,farpc-registry(服务治理),这章对IRegistrar进行了修改,将init()沉在AbstractRegistrar,在AbstractRegistrar的构造方法中调用init(),防止调用IRegistrar时,忘记调用init(),如下:

1
2
3
4
5
6
7
8
9
10
11
public interface IRegistrar {

/**
* 注册服务
* @param providerAddress 服务提供者地址
* @param service 服务
*/
void register(String providerAddress, String service);

String discover(String service);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public abstract class AbstractRegistrar implements IRegistrar {
protected static final String FOLDER = "/faregistrys";
protected static final String SEPARATOR = "/";

public AbstractRegistrar() {
String address = Property.Registry.address;
init(address);
}

public String discover(String service) {
List<String> providers = lookup(service);
ILoadbalance loadbalance = new RoundLoadBalanceImpl();
String select = loadbalance.select(providers);
return select;
}

protected abstract void init(String address);

protected abstract List<String> lookup(String service);
}

redis实现注册中心

使用redis作为注册中心跟zookeeper的逻辑是一样的,所以这章不会像之前那样一步步推理了,直接铺代码了。我们先依赖maven,我们选择jedis操作redis。

1
2
3
4
5
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.5.0</version>
</dependency>

然后这里新增了两个类,RedisOparetor、RedisRegistrarImpl,RedisOparetor用来初始化redis连接,RedisRegistrarImpl主要继承AbstractRegistrar来实现IRegistrar。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class RedisOparetor {
private static Logger logger = LoggerFactory.getLogger(RedisOparetor.class);
private static int MAX_ACTIVE = 1024;
private static int MAX_IDLE = 200;
private static int MAX_WAIT = 10000;
private static int TIMEOUT = 10000;
private static boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool = null;

public static void init(String addr) {
if (jedisPool == null) {
synchronized (RedisOparetor.class) {
if (jedisPool == null) {
try {
String[] split = addr.split(":");
String host = split[0];
Integer port = Integer.parseInt(split[1]);
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, host, port, TIMEOUT);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
}
}

public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis resource = jedisPool.getResource();
return resource;
} else {
throw new RuntimeException("call RedisOparetor.getJedis, connection is closed");
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException(e);
}
}

/***
* 释放资源
*/
public static void returnResource(final Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class RedisRegistrarImpl extends AbstractRegistrar {

public void register(String providerAddress, String service) {
RedisOparetor.getJedis().lpush(FOLDER + SEPARATOR + service, providerAddress);
}

@Override
protected void init(String address) {
RedisOparetor.init(address);
}

@Override
public List<String> lookup(String service) {
List<String> lrange = RedisOparetor.getJedis().lrange(FOLDER + SEPARATOR + service, 0, -1);
return lrange;
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void redisTest() throws IOException {
IRegistrar registrar = new RedisRegistrarImpl();
registrar.register("127.0.0.1:20880", "com.ofcoder.farpc.demo.api.IWelcome");
System.in.read();
}

@Test
public void test() throws IOException {
IRegistrar registrar = new RedisRegistrarImpl();
System.out.println(registrar.discover("com.ofcoder.farpc.demo.api.IWelcome"));
}

------------------------------------
127.0.0.1:20880

总结

其实我没啥好总结的,就是预测一下下一章,下一章讲述的是dubbo值得一吹的SPI。我们使用SPI整合redis、zookeeper。