스프링부트

최주영·2024년 12월 4일
0

springboot

목록 보기
14/14
  • 설정
    스프링부트 : 스프링을 편리하게 사용할 수 있도록 지원하는 프레임워크

✅ (장점 1)

  • 내장 서버 : 웹 서버를 내장하고 있어서 별도의 웹서버 설치 없이 main 만 실행하면 Tomcat 이 자동으로 실행됨
@SpringBootApplication
public class TestApplication { 

	public static void main(String[] args) {
		SpringApplication.run(TestApplication.class, args);
	}
}

위의 코드가 결국 스프링 컨테이너 를 생성해주고 WAS(내장톰캣) 을 생성해줘서 편하게 TOMCAT 사용


✅ (장점 2)

  • 자동 라이브러리 관리 : 손쉽게 라이브러리를 사용할 수 있음
    즉 개발자는 원하는 라이브러리만 고르기만 하고 버전은 생략해도 된다
    스프링부트가 부트 버전에 맞는 최적화된 라이브러리 버전을 선택해준다

  • spring-boot-starter-web -> 이 하나의 라이브러리를 사용하면
    스프링 웹 MVP, 내장톰캣, JSON처리, LOG 등의 모든 라이브러리가 포함됨


✅ (장점 3)

  • 자동 구성 : 을 자동으로 등록
    스프링 부트는 자동구성(Auto Configuration) 이라는 기능을 제공해줌
    일반적으로 자주 사용하는 수 많은 빈들을 자동으로 등록해줌

  • 스프링 컨테이너란 ?
    -> 자바 객체의 생명주기를 관리해줌 (빈 생성, 관리, 제거)
    -> 스프링에서는 자바 객체를 이라고 부름
    -> 스프링 컨테이너는 @Configuration 가 붙은 클래스를 설정 정보로 사용함
    -> @Configuration 을 생략해도 스프링부트가 제공하는 자동구성(Auto Configuration) 기능을 제공

	@Autowired
	DataSource dataSource;
	
	@Autowired
	TransactionManager transactionManager;
	
	@Autowired
	JdbcTemplate jdbcTemplate;
  • @Conditional : 특정 조건에 맞을 때 설정이 동작하도록 하는 어노테이션
    주로 환경별 설정을 분리할 때 사용 (개발 환경, 운영 환경)

  • @AutoConfiguration : 스프링 부트가 제공하는 자동구성 기능을 적용할 때 사용하는 애노테이션

ex)
@AutoConfiguration 
@ConditionalOnProperty(name = "memory", havingValue = "on") // 해당 조건에 환경정보가 있을 때 라이브러리 적용 (스프링 빈 등록)
public class MemoryAutoConfig {
	@Bean
	public 메소드1()
    
    @Bean
    public 메소드2()
}

위처럼 자동구성 라이브러리를 사용하려면 추가로 자동 구성 대상 지점 을 지정해줘야 한다
스프링부트는 시작지점에 org.springframework.boot.autoconfigure.AutoConfiguration.imports 의 정보를 읽어서 자동구성으로 사용 -> 따라서 위 조건이 맞으면 내부에 있는 MemoryAutoConfig 가 자동으로 실행

memory.MemoryAutoConfig // 패키지명.클래스이름  을 적어서 지정해줘야함

그럼 해당 클래스는 자동구성으로 사용하다는 의미 = 클래스 안에서 메소드들이 bean 으로 등록됨

부트에서는 @ConditionalOnProperty 많이 사용

  • @ConditionalOnProperty(name = "feature.enabled", havingValue = "true",matchIfMissing = false)

  • @Conditional, @ConditionalOnProperty 둘다 Condition 클래스를 구현함

Main에서 run() 메소드 안에 @SpringBootApplication 이 존재
-> @SpringBootApplication 안에는 @EnableAutoConfiguration 존재 -> 자동 구성을 활성화하는 기능

  • @Import : 다른 구성 클래스들을 가져와서 현재의 구성 클래스에 포함시키기 위해 사용됨
    -> 모듈화된 설정을 관리하거나 여러 구성 클래스를 하나의 애플리케이션 컨텍스트로 통합할때 유용
    -> @Import로 가져온 클래스의 빈들이 자동으로 등록됨
// TestBean 클래스
public class TestBean {
	
}
// TestConfig 클래스
@Configuration
public class TestConfig { // (3) TestConfig도 스프링 컨테이너에 등록하기 위해서 @Configuration으로 등록
	
	@Bean
	public TestBean testBean() { // (4) testBean 메소드가 빈으로 등록됨
		return new TestBean();
	}
}
// ImportTest 클래스 (Junit 테스트)
public class ImportTest {
	
	@Test
	void staticConfig() {
		// (1) 스프링 컨테이너 생성 -> 위에서 설명한대로 @Configuration 이 붙은 클래스를 설정 정보로 등록
        // 그 클래스가 바로 useConfig
		AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(useConfig.class);  
		TestBean bean = appContext.getBean(TestBean.class); // (5) 등록된 빈 가져오기 
		Assertions.assertThat(bean).isNotNull(); 
        // (6) 즉 여러가지 어노테이션을 사용해서 스프링컨테이너에 useConfig 클래스만 설정정보로 등록해도 빈이 존재
	}
	
	@Configuration
	@Import(TestConfig.class)
	public static class useConfig { // (2) useConfig는 TestConfig 클래스를 포함시킴 (빈으로 등록됨)
	}
}
  • @ImportSelector : 위 방식(정적)과 다르게 동적으로 설정 클래스를 가져올 때 사용하는 인터페이스
    -> 이 인터페이스를 구현하면 런타임에 프로그램 방식으로 가져올 설정 클래스를 결정가능함
    -> 반환받는 문자열이 클래스 정보가 됨
//  MyImportSelector 클래스
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 로직을 통해 가져올 클래스 이름들을 반환 (if문 사용 가능)
        return new String[]{"com.example.Config1", "com.example.Config2"};
    }
}
// AppConfig 클래스
@Configuration // 이번에는 스프링컨테이너에서 Appconfig를 설정정보로 등록하는 과정은 생략
@Import(MyImportSelector.class) // (1) MyImportSelector 클래스를 포함시킴
public class AppConfig {
    // 애플리케이션 설정
}

✅ (장점 4)

  • 외부 설정
    -> 하나의 어플리케이션을 개발 할 때, 서로 다른 환경에서 사용할 때가 존재
    -> 개발환경 (개발 DB사용) , 운영환경 (운영 DB사용)
    즉 환경에 따라 다른 설정값이 존재하며 다른 값을 사용해야함

과거에는 위와 같이 파일들을 환경에따라 배포함
하지만 환경에 따라서 빌드를 여러번 해야하기 때문에 좋은 방법이 아님

즉 다음과 같이 빌드는 한번만 하고 각 환경에 맞추어 실행시점에 외부 설정값 을 주입함

  • 외부 설정 하는 4가지 방법

✅ (1) : OS 환경변수 : OS를 사용하는 모든 프로그램에서 읽을 수 있는 설정값으로 사용범위가 넓음
-> CMD창에서 환경변수 조회방법
-> 윈도우 : set 입력
-> Mac or 리눅스 : printenv 입력
-> 위와 방법으로 환경변수를 조회 한 후 OS 환경변수를 설정하고 System.getenv()로 외부설정 사용
한계 : OS 환경변수는 이 프로그램뿐 아니라 다른 프로그램에서도 사용되는 전역변수 같은 효과가 있음

✅ (2) : 자바 시스템 속성 : 실행한 JVM 안에서 접근 가능한 외부 설정
Properties p = System.getProperties(); 를 사용해서 자바 시스템 속성을 조회 가능
한계 : 코드 안에서 사용하는 것으로 외부로 설정을 분리하는 효과가 없음

✅ (3) : 자바 커맨드 라인 인수 : 애플리케이션 실행 시점에 외부 설정값을 main(args)
args 파라미터로 전달하는 방법
-> 커맨드 라인에 전달하는 값은 형식이 없고, 띄어쓰기로 구분함
-> 커맨드 라인 인수는 key=value 형식이 아니다
-> 개발자가 직접 =를 기준으로 파싱해서 key=value 형식으로 맞춰야함

  • 커맨드 라인 옵션 인수
    -> 스프링부트가 커맨드 라인 인수를 key=value 형식으로 편하게 사용할 수 있도록 스프링만의 표준 방식을 정의
    -> --key=value 형식

커맨드 라인 옵션 인수, 자바 시스템 속성, OS 환경변수는 모두 외부 설정을 key=value 형식으로 사용할 수 있는 방법이다

외부 설정 값을 EnvironmentPropertySource 를 통해 외부설정을 통합할 수 있다

중복되는 값들은 우선순위를 통해서 해결된다

한계 : 사용해야하는 값들이 늘어날수록 불편함 그래서 등장한 방법이 다음에 설명할
설정값을 파일에 저장하는 방법이다

✅ (4) : 외부 파일 (설정 데이터)
-> 애플리케이션에서 특정 위치의 파일을 읽도록 함 (ex : application.properties)
-> 각 서버마다 해당 파일안에 다른 설정정보를 저장
-> 개발서버 application.properties : url=dev.db.com
-> 운영서버 application.properties : url=prod.db.com

application.properties 를 여러개 만들어 내부파일을 분리 할 수 있지만
실무에서는 주로 내부파일을 합체하는 형식으로 만든다
밑에는 하나의 application.properties 에서 여러개파일을 같이 적용하는 예시

  • #--- : application.properties 에서 파일을 구분하는 방법
  • --- : application.yml 에서 파일을 구분하는 방법
  • 프로필 : 파일을 구분하는 값
    -> 프로필 적용의 유무에 따라 동일한 값이 우선순위 로 인해 값이 바뀐다

    // 로컬환경일 때, 따로 프로필을 안줌
    url=local.db.com
    username=local_user
    password=local_pw
    #---
    spring.config.activate.on-profile=dev // 개발환경일 때
    url=dev.db.com
    username=dev_user
    password=dev_pw
    #---
    spring.config.activate.on-profile=prod // 운영환경일 때
    url=prod.db.com
    username=prod_user
    password=prod_pw

우선순위는 범위가 넓은 것보다 좁은 곳이 더 우선권을 가진다

  • 자주사용되는 우선순위 (위로갈수록 우선순위 높음)
    -> TestPropertySource (테스트에서 사용)
    -> 커맨드 라인 옵션 인수
    -> 자바 시스템 속성
    -> OS 환경변수
    -> 설정 데이터 (application.properties)

  • @Value : 외부 설정 값을 편리하게 주입받을 수 있는 어노테이션
    -> 주로 필드에서 주입받거나 파라미터 를 통해서 주입 받는다

 public class MyDataSourceValueConfig {
     @Value("${my.datasource.url}") // 필드에 주입 받은 값 사용
     private String url;
     @Value("${my.datasource.username}") // 키가 없을 경우 기본 값 지정 가능 => @Value("${my.datasource.username:최주영}")
     private String username;

   	@Bean
	public MyDataSource myDataSource1() { // 
      	return new MyDataSource(url, username);
    }	
    @Bean
    public MyDataSource myDataSource2(
        @Value("${my.datasource.url}") String url, // 파라미터 통해서 설정 값 주입 (타입은 알아서 맞춰줌)
        @Value("${my.datasource.username}") String username{
 		return new MyDataSource(url, username);
    }
 }
// application.properties
 my.datasource.url=local.db.com
 my.datasource.username=local_user
  • @ConfigurationProperties : 외부 설정을 주입받는 객체를 의미
@Data
 @ConfigurationProperties("my.datasource") // 외부설정 시작점 적어주기 
 public class MyDataSourcePropertiesV1 {
     private String url;
     private String username;
     private String password;
     private Etc etc = new Etc();
     
     @Data
     public static class Etc { // getter setter 방식
     	private int maxConnection;
     	private Duration timeout;
 		private List<String> options = new ArrayList<>()
    }
  }
@Getter
@ConfigurationProperties("my.datasource")
public class MyDataSourcePropertiesV2 {
	private String url;
	private String username;
	private String password;
	private Etc etc;
	
    // 생성자 방식
	public MyDataSourcePropertiesV2(String url, String username, String password, @DefaultValue Etc etc) {
		this.url = url;
		this.username = username;
		this.password = password;
		this.etc = etc;
	}
}
  • 자바 빈 검증기 : 설정정보를 편리하게 할 수 있는 기능
    -> build.gradle에서 spring-boot-starter-validation 먼저 추가
    -> @Min @Max @NotEmpty
    -> 클래스 위에 @Validated 어노테이션을 붙여줘야함
@Getter
@ConfigurationProperties("my.datasource")
@Validated
public class MyDataSourcePropertiesV3 {
 @NotEmpty
 private String url;
 @NotEmpty
 private String username;
 @NotEmpty
 private String password;
 private Etc etc;
 }
  • ConfigurationProperties 장점
    -> 외부 설정을 객체로 편리하게 변환해서 사용할 수 있다.
    -> 외부 설정의 계층을 객체로 편리하게 표현할 수 있다.
    -> 외부 설정을 타입 안전하게 사용할 수 있다.
    -> 검증기를 적용할 수 있다.

  • @Profile : 특정 조건에 따라서 해당 빈을 등록할지 말지 선택할 때 사용
    -> 프로필 안에는 위에서 본 @Conditional 어노테이션이 들어있음
    -> 환경별로 외부 설정을 분리 + 등록되는 스프링 빈 분리

	@Slf4j
	@Configuration
	public class PayConfig {
		@Bean
		@Profile("default")
		public LocalPayClient localPayClient() {
			log.info("LocalPayClient 빈 등록");
			return new LocalPayClient();
		}

		@Bean
		@Profile("prod")
		public ProdPayClient prodPayClient() {
			log.info("ProdPayClient 빈 등록");
			return new ProdPayClient();
		}
	}

✅ 장점 (5)

  • 모니터링과 관리 기능

  • 프로덕션 준비 기능 : 애플리케이션을 실제 운영 환경에 배포할 때 필요한 비기능적 요소들을 의미
    -> 액추에이터를 통해 쉽게 구현 가능

목적 : 서비스 운영상태를 모니터링하면서 장애 상황 파악 및 해결

구성요소 : 지표(CPU 사용량 등 성능지표), 추적(문제 발생 지점 파악), 감사(작업기록 관리) , 모니터링

구체적인 기능 : 로그 정보 설정 상태 점검, 커넥션 풀 사용 현황 파악, 스레드 덤프 생성

액추에이터 : Spring Boot 애플리케이션의 운영 환경에서 애플리케이션을 모니터링하고 관리하기 위한 기능을 제공하는 모듈

이 라이브러리(모듈)을 사용하려면
-> implementation 'org.springframework.boot:spring-boot-starter-actuator' 추가 해야함

액추에이터 기능을 웹에 노출하는 방법

// application.yml 파일
 management:
  endpoints:
    web:
      exposure:
        include: "*"

-> include: "*" 은 web에 모든 엔드포인트를 노출한다는 의미
-> 원하는 것만 노출가능 ex) include: "health.info"
-> 전체 노출하는데 지정한 것만 빼고 싶어라고 할땐 ex) exclude: "env,beans" evn와 beans는 노출 x

  • 엔드포인트 : 액추에이터가 제공하는 하나하나의 기능을 의미함
    -> 각각의 엔드포인트를 /actuator/{엔드포인트명}
    ex) http://localhost:8080/actuator/health

✅ 다양한 엔드포인트

  • beans : 스프링 컨테이너에 등록된 스프링 빈을 보여줌

  • conditions : conditions 을 통해 빈을 등록할 때 평가조건이 일치 혹은 일치하지 않은 이유를 표시

  • env : Environment 정보를 보여줌

  • health : 애플리케이션의 전반적인 건강 상태를 확인하고 제공하는 중요한 역할을 담당
    -> 기본적으로 UP 또는 DOWN 상태를 반환하여 애플리케이션 정상 작동 중인지 여부 나타냄
    -> health 정보를 자세히 보는 방법

 management:
 	endpoint:
 		health:
		 show-details: always
# 너무 자세하다 싶으면 show-details 를 show-components로 바꾸기

다음과 같이 db, diskSpace, ping 상태를 알 수 있음
헬스 컴포넌트 중에서 하나라도 문제가 있으면, 전체상태는 down 이 됨

  • info : 애플리케이션의 기본 정보를 노출
    -> java os env build git 정보들을 제공
    -> env, java, os 는 기본적으로 비활성화 되어있어서 활성화 시켜야함
    -> build 는 META-INF/build-info.properties 파일이 필요하다
## 참고로 management 바로 다음에 info 가 나와야함 
management:
  info:
    java:
      enabled: true
    os:
      enabled: true
  • loggers : 로깅과 관련된 정보를 확인하고, 또 실시간으로 변경 가능
    -> 로그를 원하는 위치에서 레벨을 설정할 수 있음
    -> hello.controller 패키지와 그 하위는 debug 레벨을 출력하도록 설정
    -> 로그를 별도로 설정하지 않으면 스프링부트는 기본적으로 INFO 로 적용
    -> TRACE DEBUG INFO WARN ERROR 오른쪽으로 갈수록 심각한 상태
logging:
 	level:
 		hello.controller: debug

✅ 액추에이터와 보안
-> 액추에이터가 제공하는 기능들은 내부 정보를 많이 노출해서 보안상 좋지 않음
-> 액추에이터의 엔드포인트 들은 외부에서 접근이 불가능한 내부망 에서 사용하는것이 안전함

외부 인터넷망에서 실행할 수 밖에 없을 땐
-> 액추에이터의 포트번호를 다른것으로 바꾸기
-> ex) management.server.port=8085 -> 기존 8080포트에서는 액추에이터 접근 불가능
-> 또 다른 방법으로는 서블릿 필터 or 스프링 시큐리티 를 통해 인증된 사용자만 접근하도록 추가 개발

  • 마이크로미터 (micrometer) 라이브러리
    -> 애플리케이션 metric 파사드라고 불리며, 애플리케이션의 메트릭(측정 지표)를
    마이크로미터가 정한 표준 방법으로 모아서 제공
    -> 스프링 부트 액추에이터마이크로미터 를 기본으로 내장해서 사용
    -> 마이크로미터 는 추상화를 통해서 구현체를 쉽게 갈아끼울 수 있어서
    모니터링 툴이 변경되어도 애플리케이션 코드는 유지할 수 있음

  • metrics : Spring Boot 애플리케이션의 성능과 상태를 모니터링하고 측정하기 위한 기능
    -> 이 엔드포인트를 사용하면 기본적으로 제공되는 메트릭들을 확인할 수 있다
    -> 즉 액추에이터 모듈 안에 metrics 기능이 존재
    -> http://localhost:8080/actuator/metrics 로 확인 가능

    다음과 같이 요청 정보, 사용자 CPU 정보, 메모리 사용량 등등 확인할 수 있음

  • 톰캣 메트릭
    -> 유용한 메트릭 으로 tomcat. 으로 시작한다
    -> 톰캣의 최대 쓰레드, 사용 쓰레드 수
    -> 동시에 처리할 수 있는 쓰레드 수 tomcat.threads.config.max
    -> 톰캣 메트릭을 사용하려면 다음 옵션을 켜야함

server:
 tomcat:
 	mbeanregistry:
 		enabled: true

액츄에이터 를 통해서 수 많은 메트릭이 자동으로 만들어진다.
하지만 지금 방식은 실시간으로만 확인이 가능할 뿐
이러한 메트릭들을 어딘가에 지속해서 보관해야 과거의 데이터들도 확인할 수 있다.
메트릭을 지속적으로 수집하고 보관할데이터베이스 가 필요하다.
그리고 이러한 메트릭들을 그래프를 통해서 한눈에 쉽게 확인할 수 있는 대시보드 도 필요하다.

프로메테우스 : 오픈소스 모니터링 시스템으로 메트릭 을 지속해서 수집하고 DB에 저장하는 역할을 함
그라파냐 : 매우 유연하며 데이터를 그래프로 보여주는 툴

프로메테우스는 메트릭을 수집해서 저장하고 그라파냐에게 쿼리(PromQL : 프로메테우스 쿼리) 를 날려서 시각적으로 그래프를 사용자에게 표현함

  • 실무에서 많이 발생하는 문제
    -> CPU 사용량 초과
    -> JVM 메모리 사용량 초과
    -> 커넥션 풀 고갈
    -> 에러로그 급증

  • 모니터링 3단계

  1. 대시보드
    -> 전체를 한번에 볼 수 있음
    -> 마이크로미터, 프로메테우스, 그라파나 등
  2. 애플리케이션 추적
    -> 각각의 HTTP 요청을 추적, 일부는 분산 추적
    -> 실무에서는 핀포인트 오픈소스 많이 사용
  3. 로그
    -> 가장 자세한 추적으로, 원하는데로 커스텀 가능
profile
우측 상단 햇님모양 클릭하셔서 무조건 야간모드로 봐주세요!!

0개의 댓글