Java Spring Boot 005-1 | Spring Boot Properties

Yunny.Log ·2022년 3월 3일
0

Spring Boot

목록 보기
23/80
post-thumbnail

Spring Boot Properties

Spring Boot의 property 설정 & Spring Boot Profiles

  • 실제 서비스를 구동할 때 사용할 수 있는 서비스
    1) 서버 컴퓨터
    2) 컨테이너 (도커)
    3) aws와 같은 클라우드 서비스

1. 하나의 파일에서 진행하는 방식

(1) spring active 추가

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo_jpa_scheme?serverTimezone=UTC&characterEncoding=UTF-8
    username : ~~
    passsword : ~~
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: false
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
    database: sql-server
  • 현재 나의 yml 기본 상황은 위와 같음
  • 이 파일을 여러가지로 다루기 가능
  • 하나의 yml 파일 안에 여러개의 파일을 넣어주기
    --- 임, ___ 아님,
spring:
  profiles:
    active: local
- //어떤 프로그램 사용해서 active 될 지
---
spring:
  config: //설정
    activate: //실행
      on-profile: local  //현재 프로파일이 로컬일 때 실행
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo_jpa_scheme?serverTimezone=UTC&characterEncoding=UTF-8
    username : ~~
    passsword : ~~
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: false
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
    database: sql-server

  • 아래와 같이 로컬에서 시행이 되기 시작한다
    => 현재는 하나의 어플리케이션 파일 안에 여러 개의 설정을 넣는 것이었음

2) test mode 코드 추가

  • 나중에코드를 만들고 실행을 해볼 때 원본 데이터파일에 하면 꼬임 현상이 발생하게 됨
  • 따라서 테스트 db에 실행해봐야 함
  • 테스트를 위한 설정도 아래 추가
//원래 설정 아래에 또 추가
---
spring:
  config:
    activate:
      on-profile: test
  datasource:
    driver-class-name: ord.h2.Driver //내장 메모리, 따로 설치 필요 없음
    url: jdbc:h2:mem:testdb
    username : sa
    passsword : password
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
  • 이 테스트를 실행되게 하기 위해서는 아까 맨 위에 active: local로 설정해놨었는데 active: test로 진행해주어야 한다.

  • 근데 지금 이 부분 test로 고치고 실행해도 우리가 h2드라이버 사용하겠다고 선언해놓고 gradle 상에 정의 안해놨기 때문에 에러가 나는 것 -> 따라서 buld.gradle에 추가해줘야 함

  • build.gradle dependencies 부분에 추가해주깅

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	runtimeOnly 'mysql:mysql-connector-java'
	runtimeOnly 'com.h2database:h2'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
  • 위처럼 수정해주고 아래의 yml 돌린다면
spring:
  profiles:
    active: test
---
spring:
  config:
    activate:
      on-profile: local
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo_jpa_scheme?serverTimezone=UTC&characterEncoding=UTF-8
    username : demo_jpa
    passsword : Qpqpqp0614!
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: false
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
    database: sql-server

---
spring:
  config:
    activate:
      on-profile: test
  datasource:
    driver-class-name: ord.h2.Driver //내장 메모리, 따로 설치 필요 없음
    url: jdbc:h2:mem:testdb
    username : sa
    passsword : password
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect

이렇게 test mode로 구동된다고 써있음

3) 도커로 돌릴 때 설정 추가


spring:
  config:
    activate:
      on-profile: docker
  datasource:

    driver-class-name: com.mysql.cj.jdbc.Driver //내장 메모리, 따로 설치 필요 없음
      //도커로 컴퓨터 실행 경우 컨테이너 내부의 ip를 찾게 됨
      //아래와 같이 아이피 해주면 도커가 자기 컨테이너 탐색해
      //우리 아이피 주소 파악해냄
      //127.0.0.1 로 하면 컨테이너 내부에 있는 애플리케이션 찾게 돼서 문제 생기게 딤
    url: jdbc:mysql://172.17.0.1:3306/demo_jpa_scheme
    username : sa
    passsword : password
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect

4) dev, prod 설정 추가

  • url 부분의 ip 주소 칸에 적절한 주소 입력
    1) dev : 해당 사이트의 주소
    2) aws : aws-host.ap-north-2.com

Finally

  • 나중에 api 다루게 되면 서버 주소 쓰잖아, 그때도 이 yml 파일에다가 서버주소 각기 다르게 해주면서 조정해주면 됩니다

2. 여러 파일로 정리

  • 아래와 같은 폴더 구조로 정리

  • local을 따로 빼주면 아래와 같아짐
    1) application.yml

spring:
  profiles:
    active: local
---
spring:
  config:
    activate:
      on-profile: test
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb
    username : sa
    passsword : password
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect

---

spring:
  config:
    activate:
      on-profile: docker
  datasource:

    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://172.17.0.1:3306/demo_jpa_scheme
    username : sa
    passsword : password
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect

2) application-local.yml


spring:
  config:
    activate:
      on-profile: local
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo_jpa_scheme?serverTimezone=UTC&characterEncoding=UTF-8
    username : demo_jpa
    passsword : Qpqpqp0614!
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: false
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
    database: sql-server
  • 이때 따로 빼주는 파일 이름은 application-빼주는애 이름으로 설정해줘야 함
  • 그래야지 본 application.yml 파일에서 on-profile: 현재모드 되어있을 때
    현재모드인 애가 외부에 있어도 파일 이름의 application-빼준 이름으로 그 애를 찾아서 실행시키기 가능이기 때문

외부 파일 탐색 순서

1) active 파일 보고
2) application.yml 쑥 보고
3) 2)에 내가 찾는 active 파일이 없다면
4) application-내가찾는이름 애를 외부에서 찾아서 걔를 사용하게 되는 것

  • 대쉬 프로파일 명으로 지정해주는 것이 중요

3. Boot Jar 만들어보기

  • 이거 누르면
    build > libs > jpa-0.01-SNAPSHOT.jar로 생성됨

  • 실행은 터미널에서 진행
PS C:\Users\DONGYUN\Desktop\spring\jpa> java -jar .\build\libs\jpa-0.0.1-SNAPSHOT.jar

  • 기초적인 배포는 이렇게 jar 파일 만들어서 퍼뜨리는 것
java -jar -Dspring.profiles.active=local -jar build/libs/jpa-0.0.1-SNAPSHOT.jar

java 실행 명령어 입력 시
application.properties의 내용 중 profiles > active의 값을 변경할 경우
옵션을 다음과 같이 준다.
-Dspring.profiles.active = local

java -jar "-Dspring.profiles.active=local" [name].jar
java -jar "-Dspring.profiles.active=local" -jar build/libs/jpa-0.0.1-SNAPSHOT.jar

ProfileComponent

ProfileComponent 클래스 만들기

  • 프로필에 따라서 생성되는 빈도 다르다는 것을 보이기 위한 예시 클래스
@Component
@Profile("local")
public class ProfileComponent {
    private static final Logger logger = LoggerFactory.getLogger(ProfileComponent.class);
    public ProfileComponent(){
        logger.info("profile component profile: local");
    }
}
  • 터미널 새로 열고 다시 명령어 입력
    (1) jar 파일 빌드
 java -jar .\build\libs\jpa-0.0.1-SNAPSHOT.jar

-> 이렇게 하면 우리가 방금 위에서 만들어두었던 로거가 찍히지 않아

(2)

  • 환경변수 설정해 놓았을 시
SPRING_PROFILES_ACTIVE=local java -jar .\build\libs\jpa-0.0.1-SNAPSHOT.jar
  • 안 설정해 놓았을 시
java -jar "-Dspring.profiles.active=local" -jar build/libs/jpa-0.0.1-SNAPSHOT.jar

(2) 코드 터미널 창에 치게 되면 이렇게 로거가 찍히게 된다, 즉 profile로 빈이 걸린 이 ProfileComponent도 함께 작동이 되는 것이당

MessageQueueInterface

MessageQueueInterface 인터페이스 만들기

package jsbdy.jpa;

public interface MessageQueueInterface {
    String readMessage();
}
  • 이 인터페이스를 상속받을 두개의 클래스 만들기

RabbitMQ

@Component
@Profile("!prod")
public class RabbitMQ implements MessageQueueInterface {
    @Override
    public String readMessage(){
        //code for communicating with RabbitMq
        return "message from rabbitmq";
    }
}

KafkaQ

package jsbdy.jpa;
@Component
@Profile("prod")
public class KafkaQ implements MessageQueueInterface {
    @Override
    public String readMessage(){
        return "message from kafkamq";
    }
}

Rabbit, Kafka 차이

  • 래빗은 개발 단계
  • 카프카는 상용 단계

어떤 Profile이 현재 Bean일 때만 그것 실행가능하다는 점 기억해두기

  • 위의 래빗, 카프카 보면 Profile 다름, 즉 각 Profile이 어떤 상황으로 진행되고 있는지 따라서 실행되는 아이들도 달라진다.
  • 서로 다른 소프트웨어를 각기 다른 상황에서 실행시키고 싶을 때 래빗과 카프카 분리한 것처럼 하면 된다

  • 테스트를 위해서 로거 붙이고, 카프카가 local/래빗은 local 아닐 때로 설정하고 돌리기
    KafkaQ

@Profile("!local")

RabbitMq

@Profile("local")

=> profile 상태를 local로 해두고 돌리면 local 상태에 해당하는 래빗이 찍힘

=> 이번에는 profile 상태를 지정해두지 않고 돌려보기 -> 우리가 기본으로 설정해둔 test 상태가 실행 -> 그럼 local이 아니므로 래빗이 아니라 카프카만 로그가 찍히게 되겠지

Configuration,Bean을 안 사용하고 외부lib 써보기

  • 우리가 지금까지 클래스에서의 bean만 사용해왔었음

  • 디펜던시에는 어떨까?

  • 자주 jsb에서 사용하는 구글 gson이라는 아이를 dependency에 추가
    build.gradle -> 그 다음 한번 빌드

dependencies {
	implementation 'com.google.code.gson:gson:2.8.2'
    ...
  • 이 라이브러리를 사용하고 싶은데 가져와서 빈을 붙여줄 수는 없자나
  • 그리고선 gson component 만들기
@Component
public class GsonComponent {
    private final Gson gson;
    public GsonComponent(){
        this.gson=new Gson();
    }
    
    public Gson getGson(){
        return this.gson;
    }
}

(+) gson 은 어떤 라이브러린가?

  • 이렇게 만들어진 gson 빈을 데려오기

PostController

public class PostController {
    private static final Logger logger = LoggerFactory.getLogger(PostController.class);
    private final PostService postservice;
    private final Gson gson;

    public PostController(
            @Autowired PostService postservice,
            @Autowired GsonComponent gson
    ){
        this.postservice = postservice;
        this.gson = gson.getGson()
    }
  • 즉 외부의 라이브러리를 사용하기 위해서 위의 과정 거쳐서 그 라이브러리를 ioc 컨테이너의 관리 하에 두어야 하는데 so complicated ;;

  • 따라서 configurationbean이라는 annotation으로 진행해보자

Configuration을 통한 Bean 생성

  • DemoConfig라는 클래스 생성
  • 여기에 @Configuration 사용할 것

@Configuration
설명출처
이 어노테이션을 단 클래스는 빈 설정을 담당하는 클래스가 된다.
이 클래스 안에서 @Bean 어노테이션이 동봉된 메소드를 선언하면, 그 메소드를 통해 스프링 빈을 정의하고 생명주기를 설정하게 된다. 자바 기반의 config가 싫다면 XML 쓰면 된다

(+)설명

Spring Bean 등록 방법(@Bean, @Configuration, @Component)

  • 어떤 임의의 클래스를 만들어서 @Bean 어노테이션을 붙인다고 되는 것이 아니고, @Bean을 사용하는 클래스에는 반드시 @Configuration 어노테이션을 활용하여 해당 클래스에서 Bean을 등록하고자 함을 명시해주어야 한다.
  • 위의 예제에서도 클래스 이름 위에 @Configuration 어노테이션을 명시하여 해당 클래스에서 1개 이상의 Bean을 생성하고 있음을 명시하고 있다. 그렇기 때문에 @Bean 어노테이션을 사용하는 클래스의 경우 반드시 @Configuration과 함께 사용해주어야 한다.
    이러한 @Bean 어노테이션의 경우 아래와 같은 상황에서 주로 사용한다.

    1) 개발자가 직접 제어가 불가능한 라이브러리를 활용할 때
    2) 초기에 설정을 하기 위해 활용할 때

  • 위의 예제에서는 Spring에서 제공하여 개발자가 직접 제어할 수 없는 라이브러리를 위해 @Bean을 사용하고 있고,
  • 설정을 위해 개발자가 개발한 AuthenticateInterceptor, HeaderFilter를 위해 @Bean을 사용하고 있다.
  • @Configuration없이 @Bean만 사용해도 스프링 빈으로 등록이 된다. 대신 메소드 호출을 통해 객체를 생성할 때 싱글톤을 보장하지 못한다. 그렇기 때문에 Spring 설정 정보를 위해서는 반드시 @Configuration을 사용해주어야 한다.

    싱글톤 :
    설명 출처
    - Singleton(이하 싱글톤) 패턴은 자바에서 많이 사용한다.
    - 싱글톤이란 어떤 클래스가 최초 한번만 메모리를 할당하고(Static) 그 메모리에 객체를 만들어 사용하는 디자인 패턴= 을 의미한다.
    - => 생성자의 호출이 반복적으로 이뤄져도 실제로 생성되는 객체는 최초 생성된 객체를 반환
    싱글톤 패턴을 사용하는 이유
    => 한번의 객체 생성으로 재 사용이 가능하기 때문에 메모리 낭비를 방지
    => 또한 싱글톤으로 생성된 객체는 무조건 한번 생성으로 전역성을 띄기에 다른 객체와 공유가 용이
    싱글톤의 문제점
    => 싱글톤도 위에서 언급된 것 처럼 전역성을 띄면서 다른 객체와 공통으로 사용하는 경우와 같은 몇 가지 케이스에서만 사용할 때 효율적
    => but 일단 싱글톤으로 만든 객체의 역할이 간단한 것이 아닌 역할이 복잡한 경우 -> 해당 싱글톤 객체를 사용하는 다른 객체간의 결함도가 높아져서 객체 지향 설계 원칙에 어긋나게 된다. (개방-폐쇄)
    => 또한 해당 싱글톤 객체를 수정할 경우 싱글톤 객체를 사용하는 곳에서 사이드 이팩트 발생 확률이 생기게 되며, 멀티 쓰래드환경에서 동기화 처리 문제등이 생기게 된다.

  • 그리고 여기서 빈의 설정을 담당하는
    @Configuration 어노테이션도 내부적으로 @Component를 가지고 있어 @Configuration이 붙은 클래스도 Spring의 빈으로 등록이 되는 것 역시 알아 둘 필요가 있다
    [ @Component 어노테이션 ]
  • 개발자가 직접 개발한 클래스를 Bean으로 등록하고자 하는 경우에는 @Component 어노테이션을 활용하면 된다. 예를 들어 폴더 생성, 파일 저장 등을 처리하기 위해 직접 개발한 FileUtils를 Bean으로 등록하고자 한다면 아래와 같이 @Component를 사용
  • 직접 개발한 클래스 단위의 빈을 등록할 때에는 @Component를 통해 해당 클래스를 빈으로 등록함을 노출하는 것이 좋을 것, 왜냐하면 해당 클래스에 있는 @Component 만 보면 해당 빈이 등록되도록 잘 설정되었는지를 찾지 않아고 확인할 수 있기 때문이다. 반면에 @Bean을 이용하면 해당 메소드를 찾는 번거로움이 생길 수 있다.
  • 추가로 @Component를 이용한다면 Main 또는 App 클래스에서 @ComponentScan으로 컴포넌트를 찾는 탐색 범위를 지정해주어야 한다. 하지만 SpringBoot를 이용중이라면 @SpringBootConfiguration 하위에 기본적으로 포함되어 있어 별도의 설정이 필요 없다.

DemoConfiguration

@Configuration
public class DemoConfig {
    @Bean
    //이렇게 Bean 붙이면 아래 함수의 반환 값이 ioc 컨테이너 관리 하에 들감
    //원래는 우리가 Controller에 가서 autowired를 통해서 등록 시켜주고
    //일일히 관리를 해주었는데 그러지 않아두 된다는 것
    //바아로 Controller 가서 autowired 하면 불러와진다
    public Gson gson(){
        return new Gson();
    }
}

PostController

    public PostController(
            @Autowired PostService postservice,
           @Autowired Gson gson
)      {this.postservice = postservice;
    }

  • 지금까지 다룬 설정들은 스프링 부트에 필요로 하는 설정
  • 이제는 우리가 따로 어플리케이션 실행할 때 필요한 설정들 알아보기

application.yml

  • 아래 항목 추가
custom:
  property:
    single: custom-property
    comlist: comma, sparated,list,to,value
    ncp:
      id: api-id
      key: api-key
      url: https://ncp.com/
    
# 이는 외부 api 사용할 때 라던지
#custom.property.single
#custom.property.comlist

DemoConfig

@Configuration
public class DemoConfig {

    @Value("${custom-property.single}")
    //yml에 설정돼있는 값을 찾아서 얘가 들어가게 됨
    private String customProperty;

    @Value("${custom.property.comlist}")
    private List<String> customCommaList;

    @Bean
    public Gson gson(){
        return new Gson();
    }
}
  • yml에서 설정된 애가 Value 어노테이션이 붙은 아이에게 들어가게 된다
  • @Value는 Bean에서 생성된 후에 들어가게 되는 것
  • 그래서 로거 보기 힘들텐데 우리는 @PostConstruct 라는 아이로 한번 찍어볼 것이야

@Configuration
public class DemoConfig {
    private static final Logger logger = LoggerFactory.getLogger(DemoConfig.class);
    @Value("${custom.property.single}")
    //yml에 설정돼있는 값을 찾아서 얘가 들어가게 됨
    private String customProperty;

    @Value("${custom.property.comlist}")
    private List<String> customCommaList;

    @Value("${custom.property.default:default-property}")
    //저 default 모시기는 우리가 yml에서 정의안해둔 것
    //그래서 콜론 뒤에 쟤가 호출되면 불러와질 것 우리가 써줌(default-property를 디폴트로)
    private String propertyDefault;

    @PostConstruct
    public void init() {
        logger.info("custom property:{}",customProperty);
        for(String commaListItem:customCommaList){
            logger.info("Comma list item:{}",commaListItem);
        }

        logger.info("default property:{}", propertyDefault);
    }

    @Bean
    public Gson gson(){
        return new Gson();
    }
}

결과

  • yml에서 정의됐던 값들이 적절하게 democonfig에서 선언한 대로 로그에 찍혀 나옴


1) 환경변수로 실행 시 profile 결정 가능

export SPRING_PROFILES_ACTIVE=test
java -jar spring-boot.jar

#or
SPRING_PROFILES_ACTIVE=test java -jar spring-boot.jar

2) 설정 파일 안에 사용할 다양한 변수 정의 가능

custom:
	property:
    	single: custom-property
        list: comma,seperated,list,to,value

3) Configuration을 통한 Bean 생성

@Value("${custom.property.single}")
private String customProperty;

@Value("${custom.property.list}")
private List<String> customPropertyList;

에러

Exception in thread "main" java.lang.UnsupportedClassVersionError: jsby/jpa/Jpa Application has been compiled by a more recent version of the Java Runti me (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 5

this version of the Java Runtime only recognizes class file versions up to 54.0
-> 얘가 필요로 하는 버전을 설치해주면 된다
Java SE 10 = 54 (0x36 hex),[3]

0개의 댓글