作者 crossoverJie

:white_check_mark: Adding tests.

... ... @@ -6,7 +6,7 @@ server.port=8082
# 是否打开swagger
swagger.enable = true
logging.level.root=info
logging.level.root=error
#消息记录存放路径
cim.msg.logger.path = /opt/logs/cim/
... ...
... ... @@ -4,8 +4,6 @@ package com.crossoverjie.cim.server.test;
import com.alibaba.fastjson.JSON;
import com.crossoverjie.cim.client.vo.res.CIMServerResVO;
import com.crossoverjie.cim.client.vo.res.OnlineUsersResVO;
import com.vdurmont.emoji.Emoji;
import com.vdurmont.emoji.EmojiManager;
import com.vdurmont.emoji.EmojiParser;
import org.junit.Test;
import org.slf4j.Logger;
... ... @@ -21,7 +19,6 @@ import java.nio.file.StandardOpenOption;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
... ... @@ -199,11 +196,11 @@ public class CommonTest {
result = EmojiParser.parseToAliases(str);
System.out.println(result);
Collection<Emoji> all = EmojiManager.getAll();
for (Emoji emoji : all) {
System.out.println(EmojiParser.parseToAliases(emoji.getUnicode()) + "--->" + emoji.getUnicode() );
}
//
// Collection<Emoji> all = EmojiManager.getAll();
// for (Emoji emoji : all) {
// System.out.println(EmojiParser.parseToAliases(emoji.getUnicode()) + "--->" + emoji.getUnicode() );
// }
}
... ...
... ... @@ -13,7 +13,7 @@ logging.level.root=info
management.security.enabled=false
# zk 地址
app.zk.addr=47.98.194.60:2182
app.zk.addr=ip:port
# zk 连接超时时限
app.zk.connect.timeout=15000
... ... @@ -37,10 +37,11 @@ app.route.way=com.crossoverjie.cim.common.route.algorithm.consistenthash.Consist
app.route.way.consitenthash=com.crossoverjie.cim.common.route.algorithm.consistenthash.TreeMapConsistentHash
# Redis 配置
spring.redis.host=47.98.194.60
spring.redis.host=xx
spring.redis.port=6379
spring.redis.pool.max-active=100
spring.redis.pool.max-idle=100
spring.redis.pool.max-wait=1000
spring.redis.pool.min-idle=10
spring.redis.password=xx
... ...
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cim</artifactId>
<groupId>com.crossoverjie.netty</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cim-zk</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.crossoverjie.netty</groupId>
<artifactId>cim-common</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- spring-boot-maven-plugin (提供了直接运行项目的插件:如果是通过parent方式继承spring-boot-starter-parent则不用此插件) -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package com.crossoverjie.cim.server.zk;
import com.crossoverjie.cim.server.zk.util.AppConfiguration;
import com.crossoverjie.cim.server.zk.thread.RegistryZK;
import com.crossoverjie.cim.server.zk.util.ZKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.net.InetAddress;
/**
* @author crossoverJie
*/
@SpringBootApplication
public class Application implements CommandLineRunner{
private final static Logger LOGGER = LoggerFactory.getLogger(Application.class);
@Autowired
private AppConfiguration appConfiguration ;
@Autowired
private static ZKit zkUtil ;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
LOGGER.info("启动应用成功");
}
@Override
public void run(String... args) throws Exception {
//获得本机IP
String addr = InetAddress.getLocalHost().getHostAddress();
Thread thread = new Thread(new RegistryZK(addr, appConfiguration.getPort()));
thread.setName("registry-zk");
//thread.start() ;
}
}
\ No newline at end of file
package com.crossoverjie.cim.server.zk.cache;
import com.crossoverjie.cim.server.zk.util.ZKit;
import com.google.common.cache.LoadingCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
* Function: 服务器节点缓存
*
* @author crossoverJie
* Date: 2018/8/19 01:31
* @since JDK 1.8
*/
@Component
public class ServerCache {
@Autowired
private LoadingCache<String, String> cache;
@Autowired
private ZKit zkUtil;
private AtomicLong index = new AtomicLong();
public void addCache(String key) {
cache.put(key, key);
}
/**
* 更新所有缓存/先删除 再新增
*
* @param currentChilds
*/
public void updateCache(List<String> currentChilds) {
cache.invalidateAll();
for (String currentChild : currentChilds) {
String key = currentChild.split("-")[1];
addCache(key);
}
}
/**
* 获取所有的服务列表
*
* @return
*/
public List<String> getAll() {
List<String> list = new ArrayList<>();
if (cache.size() == 0) {
List<String> allNode = zkUtil.getAllNode();
for (String node : allNode) {
String key = node.split("-")[1];
addCache(key);
}
}
for (Map.Entry<String, String> entry : cache.asMap().entrySet()) {
list.add(entry.getKey());
}
return list;
}
/**
* 选取服务器
*
* @return
*/
public String selectServer() {
List<String> all = getAll();
if (all.size() == 0) {
throw new RuntimeException("路由列表为空");
}
Long position = index.incrementAndGet() % all.size();
if (position < 0) {
position = 0L;
}
return all.get(position.intValue());
}
}
package com.crossoverjie.cim.server.zk.config;
import com.crossoverjie.cim.server.zk.util.AppConfiguration;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.I0Itec.zkclient.ZkClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Function:
*
* @author crossoverJie
* Date: 2018/8/24 01:28
* @since JDK 1.8
*/
@Configuration
public class AppConfig {
@Autowired
private AppConfiguration appConfiguration ;
@Bean
public ZkClient buildZKClient(){
return new ZkClient(appConfiguration.getZkAddr(), 5000);
}
@Bean
public LoadingCache<String,String> buildCache(){
return CacheBuilder.newBuilder()
.build(new CacheLoader<String, String>() {
@Override
public String load(String s) throws Exception {
return null;
}
});
}
}
package com.crossoverjie.cim.server.zk.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
/** 是否打开swagger **/
@ConditionalOnExpression("'${swagger.enable}' == 'true'")
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.crossoverjie.netty.action.zk.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("netty-action-zk api")
.description("netty-action-zk api")
.termsOfServiceUrl("https://crossoverJie.top")
.contact("crossoverJie")
.version("1.0.0")
.build();
}
}
\ No newline at end of file
package com.crossoverjie.cim.server.zk.controller;
import com.crossoverjie.cim.common.enums.StatusEnum;
import com.crossoverjie.cim.common.res.BaseResponse;
import com.crossoverjie.cim.server.zk.cache.ServerCache;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
/**
* Function:
*
* @author crossoverJie
* Date: 22/05/2018 14:46
* @since JDK 1.8
*/
@Controller
@RequestMapping("/")
public class IndexController {
@Autowired
private ServerCache serverCache ;
/**
* 获取所有路由节点
* @return
*/
@ApiOperation("获取所有路由节点")
@RequestMapping(value = "getAllRoute",method = RequestMethod.POST)
@ResponseBody()
public BaseResponse<List<String>> getAllRoute(){
BaseResponse<List<String>> res = new BaseResponse();
List<String> all = serverCache.getAll();
res.setDataBody(all);
res.setCode(StatusEnum.SUCCESS.getCode()) ;
res.setMessage(StatusEnum.SUCCESS.getMessage()) ;
return res ;
}
/**
* 获取所有路由节点
* @return
*/
@ApiOperation("获取所有路由节点")
@RequestMapping(value = "getOneOfRoute",method = RequestMethod.POST)
@ResponseBody()
public BaseResponse<String> getOneOfRoute(){
BaseResponse<String> res = new BaseResponse();
String server = serverCache.selectServer();
res.setDataBody(server);
res.setCode(StatusEnum.SUCCESS.getCode()) ;
res.setMessage(StatusEnum.SUCCESS.getMessage()) ;
return res ;
}
}
package com.crossoverjie.cim.server.zk.thread;
import com.crossoverjie.cim.server.zk.util.AppConfiguration;
import com.crossoverjie.cim.server.zk.util.SpringBeanFactory;
import com.crossoverjie.cim.server.zk.util.ZKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Function:
*
* @author crossoverJie
* Date: 2018/8/24 01:37
* @since JDK 1.8
*/
public class RegistryZK implements Runnable {
private static Logger logger = LoggerFactory.getLogger(RegistryZK.class);
private ZKit zkUtil;
private AppConfiguration appConfiguration ;
private String ip;
private int port;
public RegistryZK(String ip, int port) {
this.ip = ip;
this.port = port;
zkUtil = SpringBeanFactory.getBean(ZKit.class) ;
appConfiguration = SpringBeanFactory.getBean(AppConfiguration.class) ;
}
@Override
public void run() {
//创建父节点
zkUtil.createRootNode();
//是否要将自己注册到 ZK
if (appConfiguration.isZkSwitch()){
String path = appConfiguration.getZkRoot() + "/ip-" + ip + ":" + port;
zkUtil.createNode(path, path);
logger.info("注册 zookeeper 成功,msg=[{}]", path);
}
//注册监听服务
zkUtil.subscribeEvent(appConfiguration.getZkRoot());
}
}
\ No newline at end of file
package com.crossoverjie.cim.server.zk.util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Function:
*
* @author crossoverJie
* Date: 2018/8/24 01:43
* @since JDK 1.8
*/
@Component
public class AppConfiguration {
@Value("${app.zk.root}")
private String zkRoot;
@Value("${app.zk.addr}")
private String zkAddr;
@Value("${app.zk.switch}")
private boolean zkSwitch;
@Value("${server.port}")
private int port;
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getZkRoot() {
return zkRoot;
}
public void setZkRoot(String zkRoot) {
this.zkRoot = zkRoot;
}
public String getZkAddr() {
return zkAddr;
}
public void setZkAddr(String zkAddr) {
this.zkAddr = zkAddr;
}
public boolean isZkSwitch() {
return zkSwitch;
}
public void setZkSwitch(boolean zkSwitch) {
this.zkSwitch = zkSwitch;
}
}
package com.crossoverjie.cim.server.zk.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public final class SpringBeanFactory implements ApplicationContextAware{
private static ApplicationContext context;
public static <T> T getBean(Class<T> c){
return context.getBean(c);
}
public static <T> T getBean(String name,Class<T> clazz){
return context.getBean(name,clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}
package com.crossoverjie.cim.server.zk.util;
import com.alibaba.fastjson.JSON;
import com.crossoverjie.cim.server.zk.cache.ServerCache;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Function: Zookeeper 工具
*
* @author crossoverJie
* Date: 2018/8/19 00:33
* @since JDK 1.8
*/
@Component
public class ZKit {
private static Logger logger = LoggerFactory.getLogger(ZKit.class);
@Autowired
private ZkClient zkClient;
@Autowired
private AppConfiguration appConfiguration ;
@Autowired
private ServerCache serverCache ;
/**
* 创建父级节点
*/
public void createRootNode(){
boolean exists = zkClient.exists(appConfiguration.getZkRoot());
if (exists){
return;
}
//创建 root
zkClient.createPersistent(appConfiguration.getZkRoot()) ;
}
/**
* 写入指定节点 临时目录
*
* @param path
* @param value
*/
public void createNode(String path, String value) {
zkClient.createEphemeral(path, value);
}
/**
* 监听事件
*
* @param path
*/
public void subscribeEvent(String path) {
zkClient.subscribeChildChanges(path, new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
logger.info("清除/更新本地缓存 parentPath=【{}】,currentChilds=【{}】", parentPath,currentChilds.toString());
//更新所有缓存/先删除 再新增
serverCache.updateCache(currentChilds) ;
}
});
}
/**
* 获取所有注册节点
* @return
*/
public List<String> getAllNode(){
List<String> children = zkClient.getChildren("/route");
logger.info("查询所有节点成功=【{}】", JSON.toJSONString(children));
return children;
}
/**
* 关闭 ZK
*/
public void closeZK() {
logger.info("正在关闭 ZK");
zkClient.close();
logger.info("关闭 ZK 成功");
}
}
spring.application.name=cim-zk
# web port
server.port=9083
# 是否打开swagger
swagger.enable = true
logging.level.root=info
# 是否注册 zk
app.zk.switch=true
# zk 地址
app.zk.addr=47.98.194.60:2181
# zk 注册根节点
app.zk.root=/route
\ No newline at end of file
... ... @@ -13,7 +13,8 @@
```
spring.redis.host=47.98.194.60
spring.redis.port=6379
spring.redis.host=xx

spring.redis.port=6379
```
其实所有的配置都是通过 `SpringBoot` 来加载的,看这个配置就知道了。
... ...
... ... @@ -30,7 +30,6 @@
<module>cim-server</module>
<module>cim-client</module>
<module>cim-common</module>
<module>cim-zk</module>
<module>cim-forward-route</module>
</modules>
... ...