Springboot Actuator之四:重写与注册服务中心的健康检查逻辑(判断依据是tcp连接是否正常)

支付项目中,调用银行的支付接口时,协议不同时:

出口网关:与外围银行对接的模块(出口网关)是socket长连接与支付公司对接,该网关需要提供http接口给内部系统调用,当socket没有建立连接时(网关服务的高可用是haProxy搭建的,有些服务的socket可能未连上支付公司),此时网关的http服务不让内部其它调用系统发现。(因为,出口网关没有存储和缓存,而且交易事件必须实时的完成,返回给trade等业务系统)

gradle构建的spring cloud项目

build.gradle中增加:

    compile 'org.springframework.retry:spring-retry:1.1.2.RELEASE'
    compile 'org.springframework.boot:spring-boot-actuator:1.4.5.RELEASE'

工程结构:

 将spring-cloud-consul-core中的有关健康检查的两个java文件按如下修改后,再拷贝到自己的工程中如上图。

/*
 * Copyright 2013-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cloud.consul;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Retryable;
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
import org.springframework.retry.interceptor.RetryOperationsInterceptor;

import com.ecwid.consul.v1.ConsulClient;

/**
 * @author Spencer Gibb
 */
@Configuration
@EnableConfigurationProperties
@ConditionalOnConsulEnabled
public class ConsulAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public ConsulProperties consulProperties() {
        return new ConsulProperties();
    }

    @Bean
    @ConditionalOnMissingBean
    public ConsulClient consulClient(ConsulProperties consulProperties) {
        return new ConsulClient(consulProperties.getHost(), consulProperties.getPort());
    }

    @Configuration
    @ConditionalOnClass(Endpoint.class)
    protected static class ConsulHealthConfig {

        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnEnabledEndpoint("consul")
        public ConsulEndpoint consulEndpoint(ConsulClient consulClient) {
            return new ConsulEndpoint(consulClient);
        }

        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnEnabledHealthIndicator("consul")
        public PosConsulHealthIndicator consulHealthIndicator(ConsulClient consulClient) {
            return new PosConsulHealthIndicator(consulClient);
        }
    }

    @ConditionalOnClass({ Retryable.class, Aspect.class, AopAutoConfiguration.class })
    @Configuration
    @EnableRetry(proxyTargetClass = true)
    @Import(AopAutoConfiguration.class)
    @EnableConfigurationProperties(RetryProperties.class)
    protected static class RetryConfiguration {

        @Bean(name = "consulRetryInterceptor")
        @ConditionalOnMissingBean(name = "consulRetryInterceptor")
        public RetryOperationsInterceptor consulRetryInterceptor(
                RetryProperties properties) {
            return RetryInterceptorBuilder
                    .stateless()
                    .backOffOptions(properties.getInitialInterval(),
                            properties.getMultiplier(), properties.getMaxInterval())
                    .maxAttempts(properties.getMaxAttempts()).build();
        }
    }
}
/*
 * Copyright 2013-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cloud.consul;

import java.util.List;
import java.util.Map;

import org.springframework.boot.actuate.health.AbstractHealthIndicator;
import org.springframework.boot.actuate.health.Health;

import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.QueryParams;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.agent.model.Self;
import com.ecwid.consul.v1.agent.model.Self.Config;
import com.dxz.IoSessionHelper;
import com.dxz.utils.SpringUtil;

/**
 * @author Spencer Gibb
 */
public class PosConsulHealthIndicator extends AbstractHealthIndicator {

    private ConsulClient consul;
    
    private IoSessionHelper ioSessionHelper;

    public PosConsulHealthIndicator(ConsulClient consul) {
        this.consul = consul;
    }
    
    private IoSessionHelper getIoSessionHelper() {
        if(null == ioSessionHelper) {
            ioSessionHelper = SpringUtil.getBean("ioSessionHelper", IoSessionHelper.class);    
        }
        return ioSessionHelper;
    }
    
    private boolean ioSessionCheck() {
        return getIoSessionHelper().ioSessionCheck();
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        try {
            Response<Self> self = consul.getAgentSelf();
            Config config = self.getValue().getConfig();
            Response<Map<String, List<String>>> services = consul
                    .getCatalogServices(QueryParams.DEFAULT);
            builder
            .withDetail("services", services.getValue())
            .withDetail("advertiseAddress", config.getAdvertiseAddress())
            .withDetail("datacenter", config.getDatacenter())
            .withDetail("domain", config.getDomain())
            .withDetail("nodeName", config.getNodeName())
            .withDetail("bindAddress", config.getBindAddress())
            .withDetail("clientAddress", config.getClientAddress());
            
            if(ioSessionCheck()) {
                builder.up();
            } else {
                builder.outOfService()
                .withDetail("description", "ioSession not available");
            }
            
        }
        catch (Exception e) {
            builder.down(e);
        }
    }
}

覆盖doHealthCheck()方法,增加socket连接校验返回健康检查结果给consul,其它微服务客户端感知到哪个网关服务是可用的。

原文地址:https://www.cnblogs.com/duanxz/p/7488863.html