공부/MSA

[MSA] Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) - Microservcie간 통신 (➀ Rest Template)

sesam 2024. 1. 29. 18:50
728x90

 

 

Communication Types

1. Cynchronous(동기) HTTP commuication

  • 이는 클라이언트와 서버 간의 통신이 비동기적으로 이루어지는 경우를 나타냅니다.
  • AMQP (Advanced Message Queuing Protocol)는 메시지 큐를 사용하여 메시지를 비동기적으로 전달하는 프로토콜입니다.
  • 클라이언트가 요청을 보내면 서버는 해당 요청을 처리하고, 클라이언트는 서버의 응답을 기다리지 않고 다른 작업을 수행할 수 있습니다.
  • 💡 Rest Template
💡 Rest Template
Rest Template
은 Spring Framework에서 제공하는 클래스로, RESTful 웹 서비스와 통신하기 위한 도구입니다.일반적으로 Rest Template은 동기적인 방식으로 사용되며, 클라이언트는 요청을 보내고 해당 요청에 대한 응답을 기다립니다.Rest Template을 사용하는 경우 주로 동기적인 통신 방식을 사용하는 것이 일반적이지만, Spring에서는 비동기적인 통신을 지원하는 기능도 제공합니다. Rest Template은 동기적인 HTTP 통신을 수행하는 도구 중 하나

 

2. Asynchronous(비동기) communication over AMQP protocol

  • 이는 클라이언트와 서버 간의 통신이 비동기적으로 이루어지는 경우를 나타냅니다.
  • AMQP (Advanced Message Queuing Protocol)는 메시지 큐를 사용하여 메시지를 비동기적으로 전달하는 프로토콜입니다.
  • 클라이언트가 요청을 보내면 서버는 해당 요청을 처리하고, 클라이언트는 서버의 응답을 기다리지 않고 다른 작업을 수행할 수 있습니다.

 

 

1. Rest Template

 

user-service

application.java

RestTemplate 빈 등록

@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }

// 생략...

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

 

UserController

//    사용자 ID로 조회
    @GetMapping("/users/{userId}")
    public ResponseEntity<ResponseUser> getUser(@PathVariable("userId") String userId) {
        UserDto userDto = userService.getUserByUserId(userId);

        ResponseUser returnValue = new ModelMapper().map(userDto, ResponseUser.class);

        return ResponseEntity.status(HttpStatus.OK).body(returnValue);
    }

 

UserServiceImpl

    @Override
    public UserDto getUserByUserId(String userId) {
        UserEntity userEntity = userRepository.findAllByUserId(userId);

        if (userEntity == null)
            throw new UsernameNotFoundException("User not found");

        UserDto userDto = new ModelMapper().map(userEntity, UserDto.class); // (바꾸고 싶은 변수, 바꾸고 싶은 "클래스")

//        List<ResponseOrder> orders = new ArrayList<>();
//        String orderUrl = "http://127.0.0.1:800/order-service/%s/orders"; // user-serivce.yml로 이동
        String orderUrl = String.format(env.getProperty("order_service.url"), userId); // %s에 userId를 넣어주기 위해 String.format 사용
        System.out.println(orderUrl);
        ResponseEntity<List<ResponseOrder>> orderListResponse = restTemplate.exchange(orderUrl, HttpMethod.GET, null,
                new ParameterizedTypeReference<List<ResponseOrder>>() {
        });

        List<ResponseOrder> orderList = orderListResponse.getBody();
        userDto.setOrders(orderList);

        return userDto;
    }

 

ResponseOrder

package com.example.userservice.vo;

import lombok.Data;

import java.util.Date;

@Data
public class ResponseOrder {
    private String productId;
    private Integer qty;
    private Integer unitPrice;
    private Integer totalPrice;
    private Date createdAt;

    private String orderId;
}

 

user-servicer.yml

spring:
 datasource:
   driver-class-name: org.h2.Driver
   url: jdbc:h2:mem:testDB
   data-username: sa
   data-password: '{cipher}AQCfbGd8zx2/cry7igIke3MwGjl6vqntSAao6GZ1fFIkV3IUvgpdtGXI1vpCgNy/3v5OlATUKeUu7NAy5nMzJhkv4Eyn+24sP6u4rlRn6zWoGGvXDc3EP+
   //73Kxv0dO0nHp5kD3pq2bLT9MnOjmlCkcptr1jMPDrOPdQ8d5Rsgh+HaNdZuNHKzr2pgWd64bjzt6HlgDzNz3ntY41ojmWiecH/g0d4DShaUacZN2s9TwVKjxPDuiDXI9lr5ezGgJClx5hrXCMnWTLi
   K9EpuLIrSaUAd3wXKC2vlUalWUEQ51tYtGg/taOi85Q3v3cVJiKEePVBX2AXZpx2Pf+IBZ2/YEbs/WqdvDt2Ns1rAnMOtR5wkZ3XzK/Kjoawcb3pWvKmE='

  #  data-password: 1234
  #  data-password: '{cipher}99ee6f49abfbcc00f273cb617bf88441879a71718d40d65427d2455018e2ba41'

token:
  expiration_time: 86400000
  secret: user_token_native_user_service_default
gateway:
  ip: 192.168.0.106

order_service:
  url: http://127.0.0.1:8000/order-service/%s/orders

 

 

 

order-service

OrderController

@RestController
@RequestMapping("/order-service")
public class OrderController {

// ..생략..

@GetMapping("/{userId}/orders")
public ResponseEntity<List<ResponseOrder>> getOrder(@PathVariable("userId") String userId) {
    Iterable<OrderEntity> orderList = orderService.getOrdersByUserId(userId);

    List<ResponseOrder> result = new ArrayList<>();
    orderList.forEach(v -> result.add(new ModelMapper().map(v, ResponseOrder.class)));

    return ResponseEntity.status(HttpStatus.OK).body(result);
}

// ..생략..

}

 

 

uri 바꾸기

ip주소나 포트번호가 변경되어도 uri값 변경없이, 마이크로 서비스 이름으로 사용 가능! 편하다!!!

💡 @LoadBalnced

자바의 스프링 프레임워크에서는 @LoadBalanced 어노테이션을 사용하여 RestTemplate이나 WebClient 등을 통해 특정 서비스를 호출할 때 로드 밸런싱을 자동으로 수행하도록 설정할 수 있습니다.
이는 서비스 디스커버리와 같은 기술과 결합하여 자동으로 서비스 간 통신을 관리하는 데 도움이 됩니다.

 

 

user-service.yml

order_service:
  url: http://order-service/order-service/%s/orders
  # http://127.0.0.1/order-service/%s/orders 에서 바꿈!

 

 

user-service

UserServiceApplication.java

@Bean
@LoadBalanced  // 이거 추가!
public RestTemplate getRestTemplate() {
    return new RestTemplate();
}

 

 

728x90