Zookeeper combat: registro de servicio en el descubrimiento

confiar

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>
     
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.1</version>
        </dependency>

Implementación de registro de servicio

Clase de registro

public class RgisteToZk implements ApplicationRunner, ApplicationContextAware {


    private static final Logger LOG = Logger.getLogger(RgisteToZk.class);

    //ZooKeeper服务地址
    private static final String SERVER = "127.0.0.1:2181";

    //会话超时时间
    private static final int SESSION_TIMEOUT = 30000;

    //连接超时时间
    private static final int CONNECTION_TIMEOUT = 5000;

    //创建连接实例
    private CuratorFramework client = null;

    //服务注册的节点路径
    private static final String BASE_SERVICES = "/services";

    //需要注册的服务
    private static final List<String> services = new LinkedList<>();

    @Value("${server.port}")
    private int port;

    @PostConstruct
    public void init() {
        //获取zk连接实例
        client = CuratorFrameworkFactory.newClient(SERVER, SESSION_TIMEOUT, CONNECTION_TIMEOUT, new ExponentialBackoffRetry(1000, 3));

        //启动
        client.start();
    }

    @PreDestroy
    public void destory() {
        //关闭
        client.delete();
        client.close();
    }


    //注册服务
    public void registe() {
        try {
            Stat pathStat = client.checkExists().forPath(BASE_SERVICES);
            if (pathStat == null) {
                //创建根路径
                client.create().orSetData().withMode(CreateMode.PERSISTENT).forPath(BASE_SERVICES, "services".getBytes());
            }

            services.forEach(service -> {
                try {
                    //创建临时有顺序的节点,因为存在节点挂掉和节点服务一致的情况,所以需要临时并且有顺序
                    client.create().orSetData().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(BASE_SERVICES + "/", service.getBytes());
                } catch (Exception e) {
                    e.printStackTrace();
                    LOG.error("注册失败!");
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            LOG.error("节点创建失败!");
        }
    }

    @Override
    public void run(ApplicationArguments args) {
        registe();
    }

    //获取服务
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        String address = "";
        try {
            address = InetAddress.getLocalHost().getHostAddress() + ":" + port;
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
         //获取容器中所有的服务
        String[] allService = applicationContext.getBeanNamesForAnnotation(RestController.class);
        for (int i = 0; i < allService.length; i++) {
            String service = allService[i];
            Class bean = applicationContext.getBean(service).getClass();
            Method[] methods = bean.getMethods();
            for (Method method : methods) {
                GetMapping annotation = method.getAnnotation(GetMapping.class);
                if (annotation != null) {
                    String[] path = annotation.value();
                    services.add(address + "/" + path[0]);
                }
            }
        }
    }
}

Nota de inicio de registro

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(RgisteToZk.class)
public @interface EnableServiceRgisteToZk {

}

Clase de entidad

public class User {

    private String userName;
    private int age;

    public User(String userName, int age) {
        this.userName = userName;
        this.age = age;
    }

    public String getUserName() {
        return userName;
    }

    public User setUserName(String userName) {
        this.userName = userName;
        return this;
    }

    public int getAge() {
        return age;
    }

    public User setAge(int age) {
        this.age = age;
        return this;
    }
}

Clase de servicio

@RestController
public class ProductController {

    @GetMapping("product")
    public String product() {
        return "test";
    }
}

Comenzar la clase

@SpringBootApplication
@EnableServiceRgisteToZk
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

Descubrimiento de servicios

Clase de descubrimiento de servicios

//拉取服务
public class PullServices implements ApplicationRunner {


    private static final Logger LOG = Logger.getLogger(PullServices.class);

    //ZooKeeper服务地址
    private static final String SERVER = "127.0.0.1:2181";

    //会话超时时间
    private static final int SESSION_TIMEOUT = 30000;

    //连接超时时间
    private static final int CONNECTION_TIMEOUT = 5000;

    //创建连接实例
    private CuratorFramework client = null;

    //服务注册的节点路径
    private static final String BASE_SERVICES = "/services";

    public static final Map<String, String> services = new ConcurrentHashMap<>();


    @PostConstruct
    public void init() {
        //获取zk连接实例
        client = CuratorFrameworkFactory.newClient(SERVER, SESSION_TIMEOUT, CONNECTION_TIMEOUT, new ExponentialBackoffRetry(1000, 3));

        //启动
        client.start();
    }

    @PreDestroy
    public void destory() {
        //关闭
        client.close();
    }


    private void pull() throws Exception {

        List<String> paths = client.getChildren().forPath(BASE_SERVICES);
        if (paths == null || paths.size() == 0) {
            LOG.error("服务不存在!");
            throw new NullPointerException();
        }


        paths.forEach(path -> {
            try {
                byte[] bytes = client.getData().forPath(BASE_SERVICES + "/" + path);
                String pathData = new String(bytes, "UTF-8");
                services.put(path, pathData);

                //监听当前节点
                TreeCache treeCache = new TreeCache(client, "/test");
                //设置监听器和处理过程
                treeCache.getListenable().addListener(new TreeCacheListener() {
                    public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                        ChildData data = event.getData();
                        if (data != null) {
                            String currentPath = data.getPath();
                            String pathData = new String(data.getData(), "UTF-8");
                            switch (event.getType()) {
                                case NODE_ADDED:
                                    services.put(currentPath, pathData);
                                    break;
                                case NODE_REMOVED:
                                    services.remove(currentPath, pathData);
                                    break;
                                case NODE_UPDATED:
                                    services.put(currentPath, pathData);
                                    break;

                                default:
                                    break;
                            }
                        } else {
                            LOG.error("data is null : " + event.getType());
                        }
                    }
                });
                //开始监听
                treeCache.start();

            } catch (Exception e) {
                e.printStackTrace();
            }
        });


    }


    @Override
    public void run(ApplicationArguments args) throws Exception {
        pull();
    }
}

Anotación de descubrimiento de servicio abierto

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(PullServices.class)
public @interface EnablePullServices {
}

Herramientas de carga personalizadas

public abstract class LoadBalance {

    public final List<String> SERVICE_LIST;

    protected LoadBalance(List<String> service_list) {
        SERVICE_LIST = service_list;
    }

    public abstract String choseServiceHost();
    
}
public class RamdomLoadBalance extends LoadBalance {
    public RamdomLoadBalance(List<String> service_list) {
        super(service_list);
    }

    @Override
    public String choseServiceHost() {
        String result = "";
        if (!CollectionUtils.isEmpty(SERVICE_LIST)) {
            int index = new Random().nextInt(SERVICE_LIST.size());
            result = SERVICE_LIST.get(index);
        }
        return result;
    }
}

Clase de llamada

@RestController
public class UserController {

    @Autowired
    private RestTemplate restTemplate;
    private static final ConcurrentHashMap concurrentHashMap = (ConcurrentHashMap) PullServices.services;

    @GetMapping("test")
    public String getUser() {
        List<String> services = new LinkedList<>();
        concurrentHashMap.forEach((key, value) -> {
            services.add(((String) value));
        });
        LoadBalance balance = new RamdomLoadBalance(services);
        String host = balance.choseServiceHost();
        User user = restTemplate.getForObject("http://" + host, User.class);
        return host + ".........." + user;
    }

}

Clase de entidad

public class User implements Serializable {

    private String userName;
    private int age;

    public User(){}

    public User(String userName, int age) {
        this.userName = userName;
        this.age = age;
    }

    public String getUserName() {
        return userName;
    }

    public User setUserName(String userName) {
        this.userName = userName;
        return this;
    }

    public int getAge() {
        return age;
    }

    public User setAge(int age) {
        this.age = age;
        return this;
    }

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", age=" + age +
                '}';
    }
}

Comenzar la clase

@SpringBootApplication
@EnablePullServices
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

Resultados de la prueba

Registro de servicio

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

Descubrimiento de servicios

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_28822933/article/details/85936985
Recomendado
Clasificación