转载请标明出处:https://blog.csdn.net/LiaoHongHB/article/details/84950486
代码下载地址:https://download.csdn.net/download/liaohonghb/10843684
架构图:
zookeeper服务注册:上面这张图左边是zookeeper集群,右边work server三台是工作服务器 。工作服务器启动时,如果该工作服务器表示master机器,则在zookeeper集群环境中创建master节点,并将工作服务器的相关信息写入master节点数据(比如IP地址等);如果该工作服务器表示slave集群,则在zookeeper集群环境中创建slave(servers)根节点,然后通过zookeeper的命名服务创建server-0000000001子节点,并将工作服务器的相关信息写入该子节点。上图中,server1和server3都是slave机器,server2是master机器。
1、集群环境的搭建:
可参考博客:https://blog.csdn.net/LiaoHongHB/article/details/84849397
三台机器地址分别是:192.168.202.128:2181;192.168.202.129:2181;192.168.202.130:2181
2、新建项目zookeeper-register,在该项目下新建子模块(module):
register-client1;register-client2;register-client3;register-core;
3、register-core:
ServiceRegistry:
public interface ServiceRegistry {
/**
* 注册服务信息
*
* @param serviceName 服务名称
* @param serviceAddress 服务地址
*/
void register(String serviceName, String serviceAddress);
}
ServiceRegistryImpl:
@Service
public class ServiceRegistryImpl implements ServiceRegistry, Watcher {
private static Logger logger = LoggerFactory.getLogger(ServiceRegistryImpl.class);
private static CountDownLatch latch = new CountDownLatch(1);
private ZooKeeper zk;
private static final int SESSION_TIMEOUT = 15000;
public ServiceRegistryImpl() {
}
public ServiceRegistryImpl(String zkServers) {
try {
zk = new ZooKeeper(zkServers, SESSION_TIMEOUT, this);
latch.await();
logger.debug("connected to zookeeper");
} catch (Exception ex) {
logger.error("create zookeeper client failure", ex);
}
}
private static final String REGISTRY_PATH = "/registry";
@Override
public void register(String serviceName, String serviceAddress) {
try {
if (serviceName.equals("master")) {
logger.info("创建master节点");
if (zk.exists("/master", false) == null) {
zk.create("/master", serviceAddress.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
}
} else {
logger.info("创建slave节点");
String registryPath = REGISTRY_PATH;
if (zk.exists(registryPath, false) == null) {
zk.create(registryPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
logger.debug("create registry node:{}", registryPath);
}
//创建服务节点(临时性节点)
String servicePath = registryPath + "/" + serviceName;
if (zk.exists(servicePath, false) == null) {
zk.create(servicePath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
logger.debug("create service node:{}", servicePath);
}
//创建地址节点
String addressPath = servicePath + "/address-";
String addressNode = zk.create(addressPath, serviceAddress.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
logger.debug("create address node:{} => {}", addressNode, serviceAddress);
}
} catch (Exception e) {
logger.error("create node failure", e);
}
}
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Watcher.Event.KeeperState.SyncConnected)
latch.countDown();
}
}
4、register-client1:
application.yml:
server:
port: 5001
address: 127.0.0.1
registry:
servers: 192.168.202.128:2181,192.168.202.129:2181,192.168.202.130:2181
RegistryConfig:通过自定义的servers地址映射到RegistryServiceImpl中的zookeeper集群机器地址
@Configuration
@ConfigurationProperties(prefix = "registry")
public class RegistryConfig {
private String servers;
@Bean
public ServiceRegistry serviceRegistry() {
return new ServiceRegistryImpl(servers);
}
public void setServers(String servers) {
this.servers = servers;
}
}
WebListener:通过implement ServletContextListener 中的方法,使得程序一启动就去调用ServiceRegistry.registry方法
@Component
public class WebListener implements ServletContextListener {
private Logger logger = LoggerFactory.getLogger(getClass());
@Value("${server.address}")
private String serverAddress;
@Value("${server.port}")
private int serverPort;
@Autowired
public ServiceRegistry serviceRegistry;
@Override
public void contextInitialized(ServletContextEvent sce) {
logger.info("注册服务:{},{}", serverAddress, serverPort);
serviceRegistry.register("slave",String.format("%s:%d",serverAddress,serverPort));
// ServletContext servletContext=sce.getServletContext();
// ApplicationContext applicationContext= WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
// RequestMappingHandlerMapping mapping=applicationContext.getBean(RequestMappingHandlerMapping.class);
// Map<RequestMappingInfo,HandlerMethod> infoMap=mapping.getHandlerMethods();
// for (RequestMappingInfo info : infoMap.keySet()) {
// String serviceName=info.getName();
// logger.info("-----------------" + serviceName);
// if(serviceName!=null){
// //注册服务
// logger.info("注册服务:{},{}", serverAddress, serverPort);
// serviceRegistry.register(serviceName,String.format("%s:%d",serverAddress,serverPort));
// }
// }
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
5、register-client2和register-client3与register-client1一样,只是参数client1和client2 都是“slave”,client3参数是“master”。
6、运行结果:运行client1、client2、client3 ;结果如下: