Spring Cloud – 간단 한 서비스 프로 세 스 (서비스 발견 및 API 호출) 를 어떻게 사용 합 니까?

67363 단어 필기 하 다.
스프링 클 라 우 드 하면 스프링 부츠 를 꼭 챙 겨 야 한다. 업계 에 서 는 이 두 가지 가 낯 설 지 않 을 것 이다.Spring Cloud 에 대한 소 개 는 더 이상 많 지 않 습 니 다.Spring Cloud 검색엔진 에서 검색 한 자 료 는 낙관적 이지 않 습 니 다. 저 와 같은 초보 자 에 게 가장 필요 한 것 은 demo 입 니 다. 먼저 달 려 서 참새 가 작 지만 오장 이 모두 갖 추어 져 있 습 니 다.
스프링 클 라 우 드 의 전체 작업 절 차 를 소개 해 야 한다.우선 Spring Cloud 의 작업 절 차 를 살 펴 보고,
Service Consumer -> Proxy Server -> Client(Load Balancer) -> Servie Discovery -> Target Service
여기 가 바로 간단 한 Service API 호출 프로 세 스 입 니 다.다음은 Spring Cloud 의 구성 요소 와 위의 절차 의 대응 관 계 를 살 펴 보 겠 습 니 다.
Spring Cloud
Module
Restful API (Spring Boot)
Target Service
Eureka
Servie Discovery
Client & Load Balancer
Spring RestTemplate & Ribbon
Proxy(Edge) Server
Zuul
Service Consumer
Browser,Curl,Other Apps,etc
이상 의 간단 한 demo 를 소개 하 겠 습 니 다.
데이터 구조 및 기초 서비스:
여기 서 Spring Boot 를 사용 하여 세 개의 기초 서 비 스 를 신속하게 만 들 고 그 중에서 세 가지 논리 적 의존 관계 가 존재 합 니 다.
Company Service
Java
public class Company {

    private Long id;
    private String name;
    
    // Constructor、Getter、Setter @RestControllerpublic class CompanyService {

    @RequestMapping("/company/{id}")public Company getCompanyById(@PathVariable("id") Long id){
        sleep();
        return new Company(id, "Company");
    }
	
	 //        Serivce    private void sleep() {
        Random rand = new Random();
        int time = rand.nextInt(2000);

        try {
            Thread.sleep(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class Company {
 
    private Long id;
    private String name;
    
    // Constructor、Getter、Setter
}
 
@RestControllerpublic class CompanyService {
 
    @RequestMapping("/company/{id}")public CompanygetCompanyById(@PathVariable("id") Long id){
        sleep();
        return new Company(id, "Company");
    }
 
 //        Serivce    private void sleep() {
        Randomrand = new Random();
        int time = rand.nextInt(2000);
 
        try {
            Thread.sleep(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Employee Service
Java
public class Employee {

    private Long id;
    private Long companyId;
    private String name;
    
    // Constructor、Getter、Setter @RestControllerpublic class EmployeeService {

    @RequestMapping("/employee/{id}")public Employee getEmployeeById(@PathVariable("id") Long id) {

        sleep();
        return new Employee(id,1L,"  ");
    }

    @RequestMapping("/employee")public List getEmployeesByCompanyId(@RequestParam("companyId") Long companyId){
        List employees = new ArrayList<>();

        employees.add(new Employee(1L, companyId, "  "));
        employees.add(new Employee(2L, companyId, "  "));
        employees.add(new Employee(3L, companyId, "  "));

        sleep();
        return employees;
    }

    private void sleep() {
        Random rand = new Random();
        int time = rand.nextInt(2000);

        try {
            Thread.sleep(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
public class Employee {
 
    private Long id;
    private Long companyId;
    private String name;
    
    // Constructor、Getter、Setter
}
 
@RestControllerpublic class EmployeeService {
 
    @RequestMapping("/employee/{id}")public EmployeegetEmployeeById(@PathVariable("id") Long id) {
 
        sleep();
        return new Employee(id,1L,"  ");
    }
 
    @RequestMapping("/employee")public List getEmployeesByCompanyId(@RequestParam("companyId") Long companyId){
        List employees = new ArrayList<>();
 
        employees.add(new Employee(1L, companyId, "  "));
        employees.add(new Employee(2L, companyId, "  "));
        employees.add(new Employee(3L, companyId, "  "));
 
        sleep();
        return employees;
    }
 
    private void sleep() {
        Randomrand = new Random();
        int time = rand.nextInt(2000);
 
        try {
            Thread.sleep(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}

Product Service
Java
public class Product {

    private Long id;
    private Long companyId;
    private String sku;
    
    // Constructor、Getter、Setter 
}

@RestControllerpublic class ProductService {

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

    @RequestMapping("/product/{id}")public Product getProductById(@PathVariable("id") Long id) {

        sleep();
        return new Product(id, 1L, "T001");
    }


    @RequestMapping("/product")public List getProductsByCompanyId(@RequestParam("companyId") Long companyId) {
        List products = new ArrayList<>();

        products.add(new Product(1L, companyId, "T001"));
        products.add(new Product(2L, companyId, "T002"));
        products.add(new Product(3L, companyId, "T003"));
        return products;
    }


    private void sleep() {
        Random rand = new Random();
        int time = rand.nextInt(3000);

        try {
            Thread.sleep(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class Product {
 
    private Long id;
    private Long companyId;
    private String sku;
    
    // Constructor、Getter、Setter
}
 
@RestControllerpublic class ProductService {
 
    private static final LoggerLOG = LoggerFactory.getLogger(ProductService.class);
 
    @RequestMapping("/product/{id}")public ProductgetProductById(@PathVariable("id") Long id) {
 
        sleep();
        return new Product(id, 1L, "T001");
    }
 
 
    @RequestMapping("/product")public List getProductsByCompanyId(@RequestParam("companyId") Long companyId) {
        List products = new ArrayList<>();
 
        products.add(new Product(1L, companyId, "T001"));
        products.add(new Product(2L, companyId, "T002"));
        products.add(new Product(3L, companyId, "T003"));
        return products;
    }
 
 
    private void sleep() {
        Randomrand = new Random();
        int time = rand.nextInt(3000);
 
        try {
            Thread.sleep(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

이 세 가지 서 비 스 는 모두 정상 적 인 독립 서비스 여야 한다.
모든 서 비 스 는 등록 센터 에서 현재 서 비 스 를 등록 해 야 하기 때문에 세 서비스의 시작 프로그램 에 주 해 를 추가 해 야 합 니 다 @ EnableDiscoveryClient
설정 파일 boottstrap. yml 에 다음 설정 을 추가 합 니 다.
YAML
spring:  application:    name: company-service
  cloud:    config:      uri: ${vcap.services.${PREFIX:}configserver.credentials.uri:http://user:password@localhost:8888}
spring:  application:    name: company-service
  cloud:    config:      uri: ${vcap.services.${PREFIX:}configserver.credentials.uri:http://user:password@localhost:8888}

서비스 센터
등록 센터 는 데모 에서 가장 간단 한 서비스 발견 과 등록 에 만 사용 되 며, 시작 프로그램 에 주석 을 달 아야 합 니 다 @ EnableEureka Server
@EnableDiscoveryClient
application. yml 에서 등록 서 비 스 를 설정 합 니 다.
YAML
server:  port: 8761security:  user:    password: ${eureka.password}

eureka:  client:    registerWithEureka: false    fetchRegistry: false  server:    waitTimeInMsWhenSyncEmpty: 0  password: ${SECURITY_USER_PASSWORD:password}
server:
  port: 8761security:
  user:
    password: ${eureka.password}
 
eureka:
  client:
    registerWithEureka: false
    fetchRegistry: false
  server:
    waitTimeInMsWhenSyncEmpty: 0
  password: ${SECURITY_USER_PASSWORD:password}

\ # \ # \ # 원 격 호출 클 라 이언 트 어댑터
서비스 발견 을 사용 하여 실제 서비스 주 소 를 찾 고 API 가 되 돌아 오 는 데 이 터 를 가 져 옵 니 다.
API 구 조 를 바 꾸 기 위해 서 는 세 개의 model 을 만들어 야 합 니 다.
Java
public class CompanyAll {

    private Long id;
    private String name;
    private List productList;
    private List employeeList;

    public CompanyAll(Company company, List productList, List employeeList) {
        this.id = company.getId();
        this.name = company.getName();
        if (employeeList != null) {
            this.productList = productList.stream().map(product ->
                    new ProductDetail(product.getId(), product.getSku())
            ).collect(Collectors.toList());
        }

        if (employeeList != null) {
            this.employeeList = employeeList.stream().map(employee ->
                    new EmployeeDetail(employee.getId(), employee.getName())
            ).collect(Collectors.toList());
        }

    }
    //Getter、Setter 
}

public class EmployeeDetail {
    private Long id;
    private String name;
    
   // Constructor、Getter、Setter
}

public class ProductDetail {

    private Long id;
    private String sku;
    
    // Constructor、Getter、Setter
}
public class CompanyAll {
 
    private Long id;
    private String name;
    private List productList;
    private List employeeList;
 
    public CompanyAll(Companycompany, List productList, List employeeList) {
        this.id = company.getId();
        this.name = company.getName();
        if (employeeList != null) {
            this.productList = productList.stream().map(product ->
                    new ProductDetail(product.getId(), product.getSku())
            ).collect(Collectors.toList());
        }
 
        if (employeeList != null) {
            this.employeeList = employeeList.stream().map(employee ->
                    new EmployeeDetail(employee.getId(), employee.getName())
            ).collect(Collectors.toList());
        }
 
    }
    //Getter、Setter
}
 
public class EmployeeDetail {
    private Long id;
    private String name;
    
  // Constructor、Getter、Setter
}
 
public class ProductDetail {
 
    private Long id;
    private String sku;
    
    // Constructor、Getter、Setter
}

도구 클래스 AppUtil 만 들 기
도구 클래스 에서 LoadBalancer Client 로 호출 됩 니 다. 이것 이 바로 넷 플 릭 스 리본 이 제공 하 는 Client 입 니 다.그 는 ServiceId (프로필 에 있 는 Service Name) 에 따라 Eureka (등록 서버) 에 서비스 주 소 를 가 져 옵 니 다.여기 서도 잘못 사용 하 는 체 제 를 제공 할 수 있 습 니 다. 극한 상황 에서 모든 지연 시 fallback Uri 를 사용 할 수 있 습 니 다.
Java
@Component
public class AppUtil {

    @Autowired
    private LoadBalancerClient loadBalancer;

    public URI getRestUrl(String serviceId, String fallbackUri) {
        URI uri = null;
        try {
            ServiceInstance instance = loadBalancer.choose(serviceId);
            uri = instance.getUri();

        } catch (RuntimeException e) {
            uri = URI.create(fallbackUri);
        }

        return uri;
    }

    public  ResponseEntity createOkResponse(T body) {
        return createResponse(body, HttpStatus.OK);
    }

    public  ResponseEntity createResponse(T body, HttpStatus httpStatus) {
        return new ResponseEntity<>(body, httpStatus);
    }

    public  T json2Object(ResponseEntity response, Class<T> clazz) {
        try {

            return (T) JSON.parseObject(response.getBody(), clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    public  List json2Objects(ResponseEntity response, Class<T> clazz) {
        try {

            return JSON.parseArray(response.getBody(), clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
@Component
public class AppUtil {
 
    @Autowired
    private LoadBalancerClientloadBalancer;
 
    public URIgetRestUrl(String serviceId, String fallbackUri) {
        URIuri = null;
        try {
            ServiceInstanceinstance = loadBalancer.choose(serviceId);
            uri = instance.getUri();
 
        } catch (RuntimeException e) {
            uri = URI.create(fallbackUri);
        }
 
        return uri;
    }
 
    public  ResponseEntity createOkResponse(T body) {
        return createResponse(body, HttpStatus.OK);
    }
 
    public  ResponseEntity createResponse(T body, HttpStatushttpStatus) {
        return new ResponseEntity<>(body, httpStatus);
    }
 
    public  T json2Object(ResponseEntity response, Class<T> clazz) {
        try {
 
            return (T) JSON.parseObject(response.getBody(), clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
 
    }
 
    public  List json2Objects(ResponseEntity response, Class<T> clazz) {
        try {
 
            return JSON.parseArray(response.getBody(), clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

물론 Api 에 대한 접근 및 Response 데이터 처리 클 라 이언 트 가 필요 합 니 다.
Java
@Component
public class RemoteServiceClient {

    @Autowired
    AppUtil appUtil;

    private RestTemplate restTemplate = new RestTemplate();

    public ResponseEntity getCompanyById(Long id) {

        URI uri = appUtil.getRestUrl("COMPANY-SERVICE", "http://localhost:57773/");
        String url = uri.toString() + "/company/" + id;

        ResponseEntity<String> resultStr = restTemplate.getForEntity(url, String.class);

        Company company = appUtil.json2Object(resultStr, Company.class);

        return appUtil.createOkResponse(company);
    }


    public ResponseEntity<List> getEmployeesByCompanyId(Long id) {
        try {

            URI uri = appUtil.getRestUrl("EMPLOYEE-SERVICE", "http://localhost:58017");

            String url = uri.toString() + "/employee?companyId=" + id;

            ResponseEntity<String> resultStr = restTemplate.getForEntity(url, String.class);

            List employees = appUtil.json2Objects(resultStr, Employee.class);

            return appUtil.createOkResponse(employees);
        } catch (Throwable t) {
            throw t;
        }
    }

    public ResponseEntity<List> getProductsByCompanyId(Long id) {
        try {

            URI uri = appUtil.getRestUrl("PRODUCT-SERVICE", "http://localhost:57750");

            String url = uri.toString() + "/product?companyId=" + id;

            ResponseEntity<String> resultStr = restTemplate.getForEntity(url, String.class);

            List employees = appUtil.json2Objects(resultStr, Product.class);

            return appUtil.createOkResponse(employees);
        } catch (Throwable t) {
            throw t;
        }
    }
}
@Component
public class RemoteServiceClient {
 
    @Autowired
    AppUtilappUtil;
 
    private RestTemplaterestTemplate = new RestTemplate();
 
    public ResponseEntity getCompanyById(Long id) {
 
        URIuri = appUtil.getRestUrl("COMPANY-SERVICE", "http://localhost:57773/");
        String url = uri.toString() + "/company/" + id;
 
        ResponseEntity<String> resultStr = restTemplate.getForEntity(url, String.class);
 
        Companycompany = appUtil.json2Object(resultStr, Company.class);
 
        return appUtil.createOkResponse(company);
    }
 
 
    public ResponseEntity<List> getEmployeesByCompanyId(Long id) {
        try {
 
            URIuri = appUtil.getRestUrl("EMPLOYEE-SERVICE", "http://localhost:58017");
 
            String url = uri.toString() + "/employee?companyId=" + id;
 
            ResponseEntity<String> resultStr = restTemplate.getForEntity(url, String.class);
 
            List employees = appUtil.json2Objects(resultStr, Employee.class);
 
            return appUtil.createOkResponse(employees);
        } catch (Throwable t) {
            throw t;
        }
    }
 
    public ResponseEntity<List> getProductsByCompanyId(Long id) {
        try {
 
            URIuri = appUtil.getRestUrl("PRODUCT-SERVICE", "http://localhost:57750");
 
            String url = uri.toString() + "/product?companyId=" + id;
 
            ResponseEntity<String> resultStr = restTemplate.getForEntity(url, String.class);
 
            List employees = appUtil.json2Objects(resultStr, Product.class);
 
            return appUtil.createOkResponse(employees);
        } catch (Throwable t) {
            throw t;
        }
    }
}

결국 외부 에 포트 를 노출 하여 데 이 터 를 되 돌려 야 합 니 다. 여기 도 Restful 인터페이스 입 니 다.
Java
@RestControllerpublic class RemoteAdapter {

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


    @Autowired
    RemoteServiceClient client;

    @Autowired
    AppUtil appUtil;

    @RequestMapping("/")public String welcome() {

        return "welcome to use my demo";
    }

    @RequestMapping("/company/{id}")public ResponseEntity getCompany(@PathVariable("id") Long id) {

        ResponseEntity companyResult = client.getCompanyById(id);

        if (!companyResult.getStatusCode().is2xxSuccessful()) {
            return appUtil.createResponse(null, companyResult.getStatusCode());
        }

        List products = null;
        try {
            ResponseEntity> productsResult = client.getProductsByCompanyId(id);
            if (!productsResult.getStatusCode().is2xxSuccessful()) {
                LOG.error("    Product API   ");
            } else {
                products = productsResult.getBody();
            }
        } catch (Throwable t) {
            LOG.error("    Product API    ", t);
            throw t;
        }

        List employees = null;
        try {
            ResponseEntity> employeeResult = null;
            employeeResult = client.getEmployeesByCompanyId(id);
            if (!employeeResult.getStatusCode().is2xxSuccessful()) {
                LOG.error("    Employee API   ");
            } else {
                employees = employeeResult.getBody();
            }

        } catch (Throwable t) {
            LOG.error("    Employee API   ");
            throw t;
        }


        return appUtil.createOkResponse(new CompanyAll(companyResult.getBody(), products, employees));
    }
}
@RestControllerpublic class RemoteAdapter {
 
    private static final LoggerLOG = LoggerFactory.getLogger(RemoteAdapter.class);
 
 
    @Autowired
    RemoteServiceClientclient;
 
    @Autowired
    AppUtilappUtil;
 
    @RequestMapping("/")public String welcome() {
 
        return "welcome to use my demo";
    }
 
    @RequestMapping("/company/{id}")public ResponseEntity getCompany(@PathVariable("id") Long id) {
 
        ResponseEntity companyResult = client.getCompanyById(id);
 
        if (!companyResult.getStatusCode().is2xxSuccessful()) {
            return appUtil.createResponse(null, companyResult.getStatusCode());
        }
 
        List products = null;
        try {
            ResponseEntity> productsResult = client.getProductsByCompanyId(id);
            if (!productsResult.getStatusCode().is2xxSuccessful()) {
                LOG.error("    Product API   ");
            } else {
                products = productsResult.getBody();
            }
        } catch (Throwable t) {
            LOG.error("    Product API    ", t);
            throw t;
        }
 
        List employees = null;
        try {
            ResponseEntity> employeeResult = null;
            employeeResult = client.getEmployeesByCompanyId(id);
            if (!employeeResult.getStatusCode().is2xxSuccessful()) {
                LOG.error("    Employee API   ");
            } else {
                employees = employeeResult.getBody();
            }
 
        } catch (Throwable t) {
            LOG.error("    Employee API   ");
            throw t;
        }
 
 
        return appUtil.createOkResponse(new CompanyAll(companyResult.getBody(), products, employees));
    }
}

Ok, 여 기 는 마지막 으로 application. yml 설정 파일 이 필요 합 니 다.물론 boottstrap. yml 의 등록 설정 은 빠 질 수 없습니다.
YAML
server:  port: 0eureka:  instance:    leaseRenewalIntervalInSeconds: 10    metadataMap:      instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${random.value}}}
  client:    registryFetchIntervalSeconds: 5
server:
  port: 0
 
eureka:
  instance:
    leaseRenewalIntervalInSeconds: 10
    metadataMap:
      instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${random.value}}}
  client:
    registryFetchIntervalSeconds: 5

\ # \ # # 프 록 시 (경계) 서비스
경계 서 비 스 는 여기 서도 demo 에서 많은 기능 을 사용 하지 않 았 습 니 다. 여 기 는 퍼 가기 역할 만 사 용 했 기 때문에 너무 많은 설정 을 하지 않 아 도 됩 니 다.시작 프로그램 에 주석 @ Controller @ EnableZuulProxy 만 추가 하면 됩 니 다.
application. yml 에 서 는 서 비 스 를 설정 해 야 합 니 다. 상기 코드 에서 스 레 드 대기 시간 을 언급 하여 API 호출 시간 을 모 의 하기 때문에 ribbon 의 TimeOut 시간 을 60 초 로 설정 해 야 합 니 다.zuul 설정 에 가장 많이 사용 되 는 것 은 경로 입 니 다. Client 가 누 출 된 서비스 인터페이스 에 대해 경로 전송 을 하 는 것 입 니 다.
YAML
info:  component: Zuul Server

endpoints:  restart:    enabled: true  shutdown:    enabled: true  health:    sensitive: falsehystrix:  command:    default:      execution:        timeout:          enabled: falseribbon:  ReadTimeout: 60000  ConnectTimeout: 6000zuul:  ignoredServices: "*"  routes:    service-adapter:      path: /app/**

server:  port: 8765logging:  level:    ROOT: INFO
    org.springframework.web: INFO
info:
  component: Zuul Server
 
endpoints:
  restart:
    enabled: true
  shutdown:
    enabled: true
  health:
    sensitive: false
hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: false
ribbon:
  ReadTimeout: 60000ConnectTimeout: 6000zuul:
  ignoredServices: "*"routes:
    service-adapter:
      path: /app/**
 
server:
  port: 8765
 
logging:
  level:
    ROOT: INFO
    org.springframework.web: INFO

결과 미리 보기
원본: http://www.tuicool.com/articles/VbURJzQ

좋은 웹페이지 즐겨찾기