SpringCloud學習筆記:四、hystrix熔斷詳解及跟dubbo的對比,feign的運用

本系列博文爲學習資料,是根據老師講義,加上自己理解描述整理而成。如有不當之處希望不吝指正,持續更新改正。

Feign的使用

Feign是對服務端和客戶端通用接口的封裝,讓代碼可以複用做到統一管理。

  • 1、jar包導入
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  • 2、啓動類導入feign客戶端
import com.xiangxue.jack.service.feign.StudentService;
import com.xiangxue.jack.service.feign.TeacherServiceFeign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication(scanBasePackages = {"com.xiangxue.jack"})
//註冊到eureka
@EnableEurekaClient
//開啓斷路器功能
@EnableCircuitBreaker
//開啓feign支持,clients指定哪個類開啓feign
@EnableFeignClients(clients = {StudentService.class,TeacherServiceFeign.class})
//開啓重試功能
//@EnableRetry
public class MicroWebApplication {

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
//        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
//        factory.setConnectionRequestTimeout(2000);
//        factory.setReadTimeout(4000);
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(MicroWebApplication.class,args);
    }
}
  • 3、feign客戶端
import com.xiangxue.jack.bean.Student;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

/*
* fallback = StudentServiceFallback.class
* 不能獲取具體異常
*
* */
@FeignClient(name = "MICRO-ORDER",path = "/feign"
        /*fallback = StudentServiceFallback.class,*/
        ,fallbackFactory = StudentServiceFallbackFactory.class)
public interface StudentService {

    @GetMapping("/student/getAllStudent")
    String getAllStudent();

    @PostMapping("/student/saveStudent")
    String saveStudent(@RequestBody Student student);

    @GetMapping("/student/getStudentById")
    String getStudentById(@RequestParam("id") Integer id);

    @GetMapping("/student/errorMessage")
    String errorMessage(@RequestParam("id") Integer id);

    @GetMapping("/student/queryStudentTimeout")
    String queryStudentTimeout(@RequestParam("millis") int millis);
}
  • 4、服務端接口
import com.xiangxue.jack.bean.Student;
import com.xiangxue.jack.service.feign.StudentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
public class StudentController implements StudentService {

    @Autowired
    private StudentService studentService;

    @RequestMapping("/feign/student/getAllStudent")
    @Override
    public String getAllStudent() {
        return studentService.getAllStudent();
    }

    @RequestMapping("/feign/student/getStudentById")
    @Override
    public String queryStudentById(@RequestParam("id") Integer id) {
        return studentService.queryStudentById(id);
    }

    @RequestMapping("/feign/student/saveStudent")
    @Override
    public String saveStudent(@RequestBody Student student) {
        return studentService.saveStudent(student);
    }

    @RequestMapping("/feign/student/errorMessage")
    @Override
    public String errorMessage(@RequestParam("id") Integer id) {
        return studentService.errorMessage(id);
    }

    @RequestMapping("/feign/student/queryStudentTimeout")
    @Override
    public String queryStudentTimeout(@RequestParam("millis") int millis) {
        log.info("provider--->" + millis);
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "provider--->" + millis;
    }
}

服務端接口必須定義跟feign客戶端相同的url。

  • 5、參數傳遞
    對象類型參數

    • 調用方
      在這裏插入圖片描述
    • 服務方
      在這裏插入圖片描述
      實際上傳的是字符串

其他參數

  • 調用方
    在這裏插入圖片描述
    這裏必須指定參數名稱
  • 服務方
    在這裏插入圖片描述
  • 6、Feign的服務降級
import com.xiangxue.jack.bean.Student;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class StudentServiceFallbackFactory implements FallbackFactory<StudentService> {

    @Override
    public StudentService create(Throwable throwable) {

        if(throwable == null) {
            return null;
        }
        final String msg = throwable.getMessage();
        log.info("exception:" + msg);
        return new StudentService() {
            @Override
            public String getAllStudent() {
                log.info("exception=====getAllStudent==========" + msg);
                return msg;
            }

            @Override
            public String saveStudent(Student student) {
                log.info("exception=====saveStudent==========" + msg);
                return msg;
            }

            @Override
            public String getStudentById(Integer id) {
                log.info("exception=====getStudentById==========" + msg);
                return msg;
            }

            @Override
            public String errorMessage(Integer id) {
                log.info("exception=====errorMessage==========" + msg);
                return msg;
            }

            @Override
            public String queryStudentTimeout(int millis) {
                log.info("exception=====queryStudentTimeout==========" + msg);
                return msg;
            }
        };
    }
}

這裏在調用對應feign客戶端方法出現異常了,就會回調到create方法中,最終會回調到對應的客戶端方法中。

  • 7、Feign的異常過濾器
    這個過濾器是對異常信息的再封裝,把feign的異常信息封裝成我們系統的通用異常對象
import feign.Response;
import feign.Util;
import feign.codec.ErrorDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;


@Configuration
public class FeignErrMessageFilter {

    @Bean
    public ErrorDecoder errorDecoder() {
        return new FeignErrorDecoder();
    }

    /*
    * 當調用服務時,如果服務返回的狀態碼不是200,就會進入到Feign的ErrorDecoder中
    * {"timestamp":"2020-02-17T14:01:18.080+0000","status":500,"error":"Internal Server Error","message":"/ by zero","path":"/feign/student/errorMessage"}
    * 只有這種方式才能獲取所有的被feign包裝過的異常信息
    *
    * 這裏如果創建的Exception是HystrixBadRequestException
    * 則不會走熔斷邏輯,不記入熔斷統計
    * */
    class FeignErrorDecoder implements ErrorDecoder {

        private Logger logger = LoggerFactory.getLogger(FeignErrorDecoder.class);

        @Override
        public Exception decode(String s, Response response) {

            RuntimeException runtimeException = null;

            try {
                String retMsg = Util.toString(response.body().asReader());
                logger.info(retMsg);

                runtimeException = new RuntimeException(retMsg);

            } catch (IOException e) {
                e.printStackTrace();
            }
            return runtimeException;
        }
    }
}

過濾器把異常返回後,feign前面定義的降級方法就會調到create方法。

注:Feign 我不建議大家使用,流程簡單併發不高的方法可以用一用。

這個講義自己沒有吃透,練習代碼就暫時不上傳,後續補上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章