모든 인스턴스 필드를 초기화하는 생성자 사용 + 모든 인스턴스 필드는 final로 정의

==> (@RequiredArgumentConstructor)

각각 필드는 getter를 가지고 있다.

==> (@Getter)

의 특징을 가지고 있는 클래스라면 Record클래스로 변경 고려

 

레코드클래스를 사용하는 이점

  • 불변성(final)을 갖기 때문에 멀티스레드 환경에서 안정적이다
  • 데이터 전송 객체와 같이 데이터 전달만을 목적으로 하는 클래스에서 간결하게 표현(불변 데이터 클래스로서의 역할)
  • 반복적이면서 필요한 생성자, getter(), equals(), hashCode(), toString() 같은 메서드 자동 생성(실수 줄이기)(boilerplate code)

 

직접 구현

public class SampleRecord {
   
   // static String STATIC_VARIABLE = "static variable";

   @JsonProperty("name")
   private final String name;
   @JsonProperty("age")
   private final Integer age;
   private final Address address;
 
   public SampleRecord(String name, Integer age, Address address) {
      this.name = name;
      this.age = age;
      this.address = address;
   }
 
   public String getName() {
      return name;
   }
 
   public Integer getAge() {
      return age;
   }
 
   public Address getAddress() {
      return address;
   }

   public String getInfo(){
      return this.name;
   }
}

 

record클래스로 변경

public record SampleRecord(@JsonProperty("name")String name,
   @JsonProperty("age")Integer age,
   Address address
) {
   // static String STATIC_VARIABLE = "static variable";
   
   public String getInfo(){
      return this.name;
   }
}

()안에 final 인스턴스 변수를 넣어주면 Getter도 만들으라는 의미가 내포됨

 

 

주의할 점

record클래스 = 데이터 클래스

record클래스는 final 클래스여서 상속 불가

각 필드는 private final 필드로 정의(setter를 통해 변경 불가)

각 필드의 getter는 getName()이 아닌 필드명을 딴 name()이 된다.

레코드 클래스에서는 기본생성자 제공X

 

 

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Record.html

 

Record (Java SE 17 & JDK 17)

Direct Known Subclasses: UnixDomainPrincipal public abstract class Record extends Object This is the common base class of all Java language record classes. More information about records, including descriptions of the implicitly declared methods synthesize

docs.oracle.com

https://openjdk.org/projects/amber/design-notes/records-and-sealed-classes

 

Data Classes and Sealed Types for Java

Records give up a key degree of freedom that classes usually enjoy — the ability to decouple a classes API from its representation. A record has a name, a state description, and a body: Because a record is “the state, the whole state, and nothing b

openjdk.org

 

'Java Spring 군 > Java' 카테고리의 다른 글

Enum  (3) 2024.12.25
StringBuilder에 대해 알아보자 - 수정중  (3) 2024.11.29
properties, yml파일 위치 상의 우선순위 - 수정중  (1) 2024.11.27
Java 정렬 함수 - 수정중  (0) 2024.11.27

java에서는 타입 안전 열거형 패턴 을 편리하게 사용할 수 있도록 열거형(enum) 타입을 제공

 

열거형을 사용하는 이점

  • 문자열 타입 안전성( 컴파일 시 오류 감지 )
  • 외부에서 임의로 생성 불

 

직접 구현

public class Grade extends Enum {
    // 문자열로 직접 사용하지 않도록 객체 생성
    public static final Grade BASIC = new Grade(10, "베이직");
    public static final Grade GOLD = new Grade(20, "골드");
    public static final Grade DIAMOND = new Grade(30, "다이아몬드");
    
    // enum 종류에 따라 변하는 값이므로 안에서 선언
    private final int discountPercent;
    private final String description;
    
    // 외부에서 생성되지 않도록
    private Grade(int discountPercent, String description){
    	this.discountPercent = discountPercent;
        this.description = description;
    }
    
    public int discount(int price){
    	return price * discountPercent / 100;
    }
    
}

 

enum으로 변경

class enum Grade{
    BASIC(10, "베이직"),
    GOLD(20, "골드"),
    DIAMOND(30, "다이아몬드");
    
    private final int discountPercent;
    private final String description;
    
    Grade(int discountPercent, String description){
    	this.discountPercent = discountPercent;
        this.description = description;
    }
    
    public int discount(int price){
    	return price * discountPercent / 100 ;
    }
}

 

Enum 클래스의 주요 함수

  • values()  : ex) return : [ BASIC, GOLD, DIAMOND]
  • valueOf(String name) : ex) valueOf("BASIC")
  • name() : ex) return : BASIC
  • toString() : override 로 재정의 가능

Swagger 공식 홈페이지에 가봤는데 swagger가 하나만 있는줄 알았는데 여러 툴이 있었다.

아무 것도 모르는데 여기서 어떻게 찾아야 할지 막막했다.

뭔가 Swagger UI인 것 같은데 또 quick start같은 것을 보면 또 아닌 것 같았다.

yaml로 작성한 적이 없는데 yaml로 직접 작성해야 하는게 너무 당황스러웠다.

 

어떻게 찾아야할지 고민하다가 일단 index화면에서 살펴보니 swagger가 spring에서만 사용하는 것이 아니었다.

그래서 spring에서 사용하던 어노테이션 방식을 알아야 해서

gpt에게 물어보았다. spring에서 swagger를 어떻게 사용하고 공식문서는 어디있는지 알려달라고 물었다.

springdoc-openapi를 알려주었다.

https://springdoc.org/#getting-started

 

OpenAPI 3 Library for spring-boot

Library for OpenAPI 3 with spring boot projects. Is based on swagger-ui, to display the OpenAPI description.Generates automatically the OpenAPI file.

springdoc.org

 

들어가서 문서를 살펴보니 찾고 싶었던 것 같은데 예시코드가 한눈에 안 들어왔다.

그래서 처음부터 읽어가기로 했다.

 

Springdoc-openapi

  • Springdoc-openapi는 java 라이브러리이고 Spring Boot 프로젝트를 사용하여 API 문서 생성을 자동화해준다.
  • Spring Boot2 이하는 Springdoc-openapi v1.8.0까지만 지원된다.
  • Springdoc-openapi는 런타임에 애플리케이션을 검사할 때 작동한다.
  • 자동으로 JSON / YAML 그리고 HTML 포맷으로 API들을 문서로 생성한다. (-> Swagger가 공홈에서 왜 yaml파일로 작성되어있는지 알게 되었다.)
  • 이 라이브러리는
     - openAPI 3
     - Spring Boot 3
     - JSR-303 (특히, @NotNull, @Min, @Max, @Size)
     - Swagger-UI
     - OAuth2
     - GraalVM native images
    를 지원한다.
  • Swagger 제품 중 Swagger UI를 사용  ( -> 기본 포맷을 작성하지 않는 것으로 보아 UI툴을 사용한다는 예상이 맞았던 것 같다.)

 

Springdoc-openapi 적용하기

  • build.gradle에
implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.7.0'
# 혹은
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0")
# 을 추가한다. ( 작성 당시 최신 안정화 파일이 2.7.0 버전이다. )

 

Swgagger UI 페이지는 'http://server:port/context-path/swagger-ui.html'에서 이용 가능

'http://server:port/context-path/v3/api-docs'에서 json 파일을 생성 가능

'http://server:port/context-path/v3/api-docs.yaml'에서 yaml파일을 생성 가능

 

  • 코드에 추가하기
@Tag(name = "User", description = "User API")	// Controller 단위로 관리
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/users")
public class UserController {

	private final UserService userService;

	// @Operation를 이용해 해당 API가 어떤 리소스를 나타내는지 간략한 설명을 추가할 수 있다.
	@Operation(summary = "Get user", description = "특정 유저의 상세 정보를 조회한다.")
	// @ApiResponses를 이용해 해당 API의 Response 정보들을 나타낼 수 있다.
	@ApiResponses(value = {
		// @ApiResponse는 단일 Response에 대한 정보를 나타낸다.
		@ApiResponse(responseCode = "200", description = "성공",
			// content는 response의 데이터 포맷을 알려준다
			content = {@Content(schema = @Schema(implementation = UserRes.class))}),
			// 만약 데이터 타입이 List인 경우
			// {@Content(mediaType = "application/json", 
			// 		array = @ArraySchema(schema = @Schema(implementation = UserRes.class)))}
		@ApiResponse(responseCode = "404", description = "해당 ID의 유저가 존재하지 않습니다."),
	})
	@GetMapping("/{userId}")
	public UserRes getUser(
		// @Schema와 @Parameter로 설명 가능하다.
		@Positive(message = "유저 ID는 양수입니다.")
		@Schema(description = "User ID", example = "1")
		@PathVariable Long userId,

		@Positive(message = "유저 ID는 양수입니다.")
		@Parameter(name = "loginId", description = "로그인 유저 ID 값", 
				example = "3", required = true)
		@RequestParam final Long loginId
        
		//, @RequestBody @Valid UserUpdateReq request
	) {
		return userService.getUser(userId, loginId);
	}
}

 

RequestDTO와 responseDTO에 대한 명세

// @Schema로 클래스와 필드를 설명할 수 있다.
@Schema(description = "User response")
@Getter
@AllArgsConstructor
public class UserRes {

  @NotBlank(message = "사용자 이름을 입력해주세요.")
  @Length(max = 20, message = "사용자 이름은 20글자 이하로 입력해야 합니다.")
  @Schema(description = "user name", example = "Kim")
  private String name;

  @NotBlank(message = "사용자 닉네임을 입력해주세요.")
  @Length(max = 20, message = "사용자 닉네임은 20글자 이하로 입력해야 합니다.")
  @Schema(description = "user nickname", example = "kim")
  private String nickname;
  
}

 

참고글 : https://hogwart-scholars.tistory.com/entry/Spring-Boot-SpringDoc%EA%B3%BC-Swagger%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-API-%EB%AC%B8%EC%84%9C%ED%99%94-%EC%9E%90%EB%8F%99%ED%99%94%ED%95%98%EA%B8%B0

 

 

  • 액추에이터 지원(Spring-boot-actuator)

Spring-boot-actuator 엔드포인트도 추가하려면

springdoc.show-actuator=true

을 추가하면 Swagger-UI와 Openapi 엔드포인트를

어플리케이션 포트를 통해서 확인가능 'http://server:port/actuator/swagger-ui'

 

액추에이터 관리 포트를 분리하는 것을 권장(CORS 허용 확인)

액추에이터 관리 포트에서 Swagger-UI를 보이려면

springdoc.use-management-port=true

 

를 추가해주어야 한다.

그러면

  'http://server:management-port/actuator/swagger-ui'

에서 이용 가능하다.

예를 들어, management-port=9090으로 되어 있으면

'http://localhost:9090/actuator/swagger-ui'

에서 swagger ui를 볼 수 있다.

 

  • 공식문서 예제코드

https://github.com/springdoc/springdoc-openapi

 

GitHub - springdoc/springdoc-openapi: Library for OpenAPI 3 with spring-boot

Library for OpenAPI 3 with spring-boot. Contribute to springdoc/springdoc-openapi development by creating an account on GitHub.

github.com

https://github.com/springdoc/springdoc-openapi-demos

 

GitHub - springdoc/springdoc-openapi-demos: Demo for OpenAPI 3 with spring-boot

Demo for OpenAPI 3 with spring-boot. Contribute to springdoc/springdoc-openapi-demos development by creating an account on GitHub.

github.com

javascript용 : https://github.com/swagger-api/swagger-ui

 

GitHub - swagger-api/swagger-ui: Swagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beauti

Swagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API. - swagger-api/swagger-ui

github.com

 

더티 체크 : 상태 변경 검사

JPA에서 영속성 컨텍스트가 관리하는 엔티티에만 적용한다.

JPA에서 영속성 컨텍스트에는 

각 EntityManager가 존재하는 시간에 일어난다.

EntityManager가 존재하는 시간에 하나의 Transaction이 존재하게 되는데

이 지역에서 발생하는 것을 1차 캐시에서 처리를 한다.

JPA 전체에 적용되는 캐시는 2차 캐시에서 처리가 되고

transaction 구간에서 잠깐 지역적으로 존재하는 것은 1차 캐시에서 처리한다.

이 1차캐시에는 id와 Entity 그리고 Snapshot이라는 공간이 존재한다.

이 때 객체형태의 Entity로 작업이 진행된다.

JPA에서 영속성에 속하는 Entity를 CRUD를 실행할 때 잠시 작업을 모아두는 곳이다.

여기에 저장이 되면 id에 Entity의 id와 Entity에 Entity가 그리고 Snapshot에 1차캐시에 저장되는 최초 Entity 상태가 저장이 된다.

Transaction 시간 동안 여러 변경이 일어나고

Commit을 진행하는 순간

Commit시점 저장되어 있는 Entity들이 최초 저장된Snapshot과 비교해서 변경이 일어났는지 확인을 하고 

변경이 일어났으면 Update구문을 자동으로 생성해서 Commit을 하기 전에 DB에 전달할 명령에 update구문을 추가해서 진행한다.

그러고 commit이 진행이 된다.

이렇게 변경을 감지하는 것을 Dirty Check이라고 한다.

눈에 들어올 수 있도록 정리해야 할 것 같다.

'Java Spring 군 > Java' 카테고리의 다른 글

Record 클래스(Java 14이상 적용가능)  (1) 2025.01.15
Enum  (3) 2024.12.25
properties, yml파일 위치 상의 우선순위 - 수정중  (1) 2024.11.27
Java 정렬 함수 - 수정중  (0) 2024.11.27

4.1 클라이언트 사이드 로드 밸런싱 개요

4.1.1 로드 밸런싱이란?

  • 로드 밸런싱은 네트워크 트래픽을 여러 서버로 분산시켜 서버의 부하를 줄이고, 시스템의 성능과 가용성을 높이는 기술
  • 서버 간 트래픽을 고르게 분배하여 특정 서버에 부하가 집중되는 것을 방지
  • 종류: 클라이언트 사이드 로드 밸런싱, 서버 사이드 로드 밸런싱

4.1.2 클라이언트 사이드 로드 밸런싱이란?

  • 클라이언트 사이드 로드 밸런싱은 클라이언트가 직접 여러 서버 중 하나를 선택하여 요청을 보내는 방식
  • 클라이언트는 서버의 목록을 가지고 있으며, 이를 바탕으로 로드 밸런싱을 수행

 

4.5 로드 밸런싱 알고리즘

4.5.1 라운드 로빈

  • 라운드 로빈: 각 서버에 순차적으로 요청을 분배하는 방식
  • 간단하고 공평하게 트래픽을 분산

4.5.2 가중치 기반 로드 밸런싱

  • 가중치 기반 로드 밸런싱: 각 서버에 가중치를 부여하고, 가중치에 비례하여 요청을 분배하는 방식
  • 서버의 성능이나 네트워크 상태에 따라 가중치를 조절

4.5.3 기타 알고리즘

  • 최소 연결: 현재 연결된 클라이언트 수가 가장 적은 서버로 요청을 보내는 방식
  • 응답 시간 기반: 서버의 응답 시간을 기준으로 가장 빠른 서버로 요청을 보내는 방식

'Java Spring 군 > MSA' 카테고리의 다른 글

MSA 적용하기  (1) 2024.11.27

찾아봤었는데 프로젝트 진행에 급해서 다시 찾아봐야 할 것 같다.

'Java Spring 군 > Java' 카테고리의 다른 글

Record 클래스(Java 14이상 적용가능)  (1) 2025.01.15
Enum  (3) 2024.12.25
StringBuilder에 대해 알아보자 - 수정중  (3) 2024.11.29
Java 정렬 함수 - 수정중  (0) 2024.11.27

이 궁금증을 해결해준 GPT에게 감사 인사를 한다.

 

내가 보기에 계층적인 구조 때문이라도 yml파일이 사람이 보기 편한 것 같은데

개발자들이 모여있는 Spring에서

왜 properties파일과 yml파일 중 default로 properties파일 사용해야 하는 이유가 궁금해졌다.

 

궁금증에 대한 답은 역사적인 배경기본적인 디자인 원칙 때문이다. 개발 환경에 맞게 유연하게 선택하면 된다.

  properties파일 yml(yaml)파일
구조 key=value 구조 계층적 구조
장점 간결함
파싱이 더 쉬움(yml파일은 공백이나 들여쓰기에 민감하고 눈으로 확인이 어려움)
직관적

 

 

1. 역사적 배경

 - Spring의 설계 철학은 "기본값은 간단하게(Simple by default)"이다. (이게 맞는지는 한번 찾아봐야 겠다.)

 - 초창기 Spring Framework는 설정파일로 application.properties를 기본으로 사용했다.
 - 그 당시 YAML은 표준적으로 널리 사용되지 않았다.

 - 많은 Java 애플리케이션에서 properties 형식을 기본으로 사용했었다.

 - 기존 환경과의 호환성 때문이기도 하다.

 - 많은 Java 라이브러리와 툴( 예: Apache Commons Configuration, Log4j 등)이 properties 형식을 기본적으로 지원하고 있었다.

 - Spring은 이러한 표준에 맞춰 초기 설계되었기 때문이다.

 - Spring boot 2.0부터 yml(yaml)파일을 지원하기 시작했다.

 

2. 기본적인 디자인 원칙 - 간단한 구조와 사용성

 - 간결함 : properties 파일은 key-value 쌍으로 이루어진 단순한 구조를 가지고 있어 작성 및 파싱이 간단하다.

 - 범용성 : 대부분의 Java 환경에서 널리 지원된다.

 - YAML의 도입과 상대적 복잡성

    -- YAML의 도입 : Spring Boot 2.0부터 YAML파일을 지원하기 시작했다. YAML파일은 계층적 데이터 구조

    -- 파싱 및 오류 처리의 복잡성 : YAML은 가독성이 높지만, 공백이나 들여쓰기에 민감하며

        잘못된 형식으로 작성된 경우 오류를 발생시키기 쉽다.

 

3. 정책적인 이유

 - Spring의 설계 철학은 "기본값은 간단하게(Simple by default)"이다. 따라서 Spring은 기본적으로 복잡도가 낮은 properties 파일을 우선적으로 고려하지만, 복잡한 구조를 필요로 하는 경우 YAML을 사용할 수 있도록 선택지를 제공한다.

 

4. 우선순위의 유연성

Spring Boot는 기본적으로 설정파일을 application.properties , application.yml 순으로 우선순위를 가진다.

우선순위를 변경할 수 있다.

@PropertySource 애노테이션이나 spring.config.additional-ocation 속성을 사용하여 바꿀 수 있다.

이럴 경우는 properties파일과 yml파일을 같이 쓸 경우에 해당한다.


시간도 없는데 이런 궁금증이 왜 계속 생기는지ㅠ

그냥 넘어가려고 했는데 계속 눈에 밟히는 건지ㅠ

중요한 것도 물리적인 시간이 부족해서 처리하지 못하고 있는데

고민하는 시간 제외하고 또 1시간을 낭비하게 되었다ㅠ

'Java Spring 군 > Spring' 카테고리의 다른 글

Spring 사용하기  (1) 2024.11.06

+ Recent posts