SSARTEL-10th / JPTS_bookstudy

"개발자가 반드시 알아야 할 자바 성능 튜닝 이야기" 완전 정복
7 stars 0 forks source link

Spring은 설정 파일을 어떻게 사용할까? #15

Open Yg-Hong opened 1 year ago

Yg-Hong commented 1 year ago

👍 문제

Spring은 XML을 중심으로 설정 정보를 보관하던 때가 있었다. 현재는 XML 설정을 완전히 배제한 채로 처리하도록 장려하고 있다. 그 대안으로는 .properties나 .yaml, .yml 파일이 있는데 이렇게 바뀐 이유는 무엇일까?

또, .properties, .yaml 등 이런 파일이 스프링에서 설정 정보를 보관할 수 있도록 만든 원리는 무엇일까? <- 이건 어려우면 패스하자..ㅎ

✈️ 선정 배경

지난주 암살주제 때문에 이슈 난이도를 좀 낮추고자 서버 개발자에게 친숙한 Spring을 가지고 오고 싶었다.

📺 관련 챕터 및 레퍼런스

story. 13 XML과 JSON도 잘 쓰자.

🐳 비고

서버 개발자가 되고 싶은 사람이 이 주제를 다루면 찰떡일 거 같아요!

KIMSEI1124 commented 1 year ago

Spring XML Config

직접 Spring XML 설정해 보기

먼저 .properties.ymal 파일을 알아보기 전 XML으로 DB 관련 환경 설정을 진행해보겠습니다. 먼저 환경 설정 XML 파일을 생성합니다.

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  

</beans>

생성한 XML 파일이며 여기서 DB 관련 환경 설정을 진행하도록 하겠습니다.

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans.xsd">  

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">  
    <constructor-arg>  
    <bean class="com.zaxxer.hikari.HikariConfig">  
    <property name="jdbcUrl" value="jdbc:h2:tcp://localhost/~/code/study/db/config"/>  
    <property name="username" value="sa"/>  
    <property name="password" value="1234"/>  
    <property name="driverClassName" value="org.h2.Driver"/>  
    </bean>  
    </constructor-arg>  
    </bean>  
</beans>

다음과 같이 XML 파일 안에 DB 관련 환경 설정을 하고 추가적으로 @ImportResource 에다가 해당 XML 파일을 등록해줍니다.

@SpringBootApplication  
@ImportResource("classpath:application.xml") // XML 파일을 임포트  
public class ConfigApplication {  

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

하지만 .. 실행이 정상적으로 되지 않았습니다. 뭔가 더 해야하는 것이 있는것을 추후 발견했습니다만 번거로운 작업이 필요합니다.

대략 30분 동안 XML 파일을 가지고 Spring 환경 설정을 해보려고 했지만 가독성도 매우 떨어지고 환경설정 방식도 매우 어려웠습니다.

왜 사용하지 않는가?

먼저 XML, yaml, propreties와 같은 파일 포맷에 대한 간단한 설명을 하겠습니다.

아래의 코드들은 각각 Spring 에서 DB와 관련된 설정을 하기 위한 설정입니다.

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans.xsd">  

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">  
    <constructor-arg>  
    <bean class="com.zaxxer.hikari.HikariConfig">  
    <property name="jdbcUrl" value="jdbc:h2:tcp://localhost/~/code/study/db/config"/>  
    <property name="username" value="sa"/>  
    <property name="password" value="1234"/>  
    <property name="driverClassName" value="org.h2.Driver"/>  
    </bean>  
    </constructor-arg>  
    </bean>  
</beans>
spring:  
  datasource:  
    driver-class-name: org.h2.Driver  
    url: jdbc:h2:tcp://localhost/~/code/study/db/config  
    password: 1234  
    username: sa
spring.datasource.driver-class-name=org.h2.Driver  
spring.datasource.url=jdbc:h2:tcp://localhost/~/code/study/db/config  
spring.datasource.username=sa  
spring.datasource.password=1234

각각의 파일에 따른 설정들이며 공통된 점으로는 key-Value 형식으로 이루어져 있습니다. 이러한 이유는 타 시스템 간에 데이터를 주고 받을 때 데이터 포맷에 대한 약속이 필요하기 때문입니다.2)

과거에 Spring 에서는 XML을 사용하여 환경 설정과 같은 작업을 하였는데 현재 Spring 에서 XML 대신에 다른 포맷을 사용하는 이유 다음과 같습니다.

간결성과 가독성


Properties 파일 및 YAML 파일은 XML 보다 더 간결하고 가독성이 좋습니다. XML은 태그 기반으로 작성되고 여는 태그와 닫는 태그가 필요하며 이로 인해서 불필요한 장황함이 발생할 수 있습니다.

위의 3가지 코드를 봐도 XML이 가장 가독성이 좋지 않다는 것을 확인할 수 있습니다.

편리한 리스트 및 맵 표현


Properties 파일 및 YAML 파일은 리스트와 맵을 나타내기 위한 간단한 표기법을 제공합니다. 예를 들면 YAML에서는 들여쓰기를 사용하여 리스트 및 맵을 정의할 수 있습니다.

yaml 예시2)

XML에서는 복잡한 태그 구조를 사용하며 리스트와 맵을 나타내어야 하므로 번거롭고 복잡할 수 있습니다.

더 많은 프로그래밍 언어 및 플랫폼과 호환


Properties 파일은 다양한 프로그래밍 언어와 플랫폼에서 사용 가능하며, YMAL도 널리 사용됩니다.

현재는 YAML이 더 많이 사용하는 것 같습니다.

XML은 주로 Java 생태계에서 사용되며, 다른 환경에서는 해석하기가 어렵고 불편할 수 있습니다.

이러한 이유로 XML은 점점 주류에서 벗어나게 되었습니다.

Spring Boot 의 기본 지원


이제 Spring BootPropertiesYAML파일을 기본으로 지원하고 설정을 더 쉽게 관리할 수 있습니다. XML을 사용하려면 추가 설정이 필요하며, Spring Boot의 자동 설정과 통합이 어렵습니다.

Spring 에서 XML을 사용하지 않는 가장 큰 이유라고 생각하고있습니다.

요약

PropertiesYAML파일은 Spring 프로젝트에서 설정을 더 간편하게 관리하고 가독성을 높일 수 있는 선택입니다.

XML은 특별한 경우나 레거시 시스템과의 통합 등 특수한 상황에서 사용될 수 있지만, 주로 PropertiesYAML을 선호하는 추세입니다.

Ref

  1. [Spring] context-datasource.xml 설정 : DBCP configuration 살펴보기 ~ Haenny
  2. yaml파일 이란 무엇인가요 ~ 인프런
KIMSEI1124 commented 1 year ago

들어가며

추가적으로 요청했던 .properties, .yaml 등 이런 파일이 스프링에서 설정 정보를 보관할 수 있도록 만든 원리는 무엇일까? 에 대한 내용에 대해서 찾아보고 정리합니다.

실제로 개발을 진행할 때 ymal 파일을 자주 사용하는데 관심이 있었던 주제이기 때문에 자세하게 찾아보며 코드도 찾아봅니다.

Property

기존에 Spring 에서는 XML로 모든 설정을 관리했는데 Spring Boot에서는 정적인 값을 key-value형식으로 관리합니다.

Properties, YMAL

그러면 Spring Boot는 어떻게 해당 값들을 사용하는 것 일까요?

Auto Configuration

해답은 @SrpingBootApplication 어노테이션에 있습니다.

@SpringBootApplication  // 이 어노테이션
public class ConfigApplication {  
    public static void main(String[] args) {  
    SpringApplication.run(ConfigApplication.class, args);  
    }  
}

해당 어노테이션이 어떻게 구성되어 있는지 확인하면 다음과 같습니다.

@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Inherited  
@SpringBootConfiguration  
@EnableAutoConfiguration  
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),  
       @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) 
public @interface SpringBootApplication {

위의 어노테이션 중 @EnableAutoConfiguration 이 자동 환경 설정을 도와줍니다. Spring Boot 에서 개선된 점이며 Spring Boot가 가지는 가장 큰 장점입니다.

자동으로 환경을 설정해주기 때문에 번거롭게 설정을 할 필요가 없어져 개발자들은 개발에만 집중할 수 있게 됩니다.

이 어노테이션 하나로 Web, H2, JDBC 를 비롯한 수 많은 자동 설정을 제공합니다.

만약, H2 DB의 의존성이 클래스 경로에 존재한다면 자동으로 In-Memory DB에 접근하게 됩니다. 이러면 개발자가 H2 DB의 설정을 파일에 따로 입력하지 않아도 해당 애플리케이션이 In-Memory DB에 접근합니다.

혹시나 더 자세한 코드를 확인하고 싶은 분들은 AutoConfigurationPackages.java 관련 추상 클래스를 확인해보시면 좋을 것 같습니다. 설정 파일이 존재하지 않으면 예외를 던지고 있으며 설정파일을 등록, 추가 하는 기능이 존재합니다.

Spring Boot 의 기본 포트가 8080인 이유


Embedded Tomcat에서 기본 설정 값으로 8080 포트를 사용하게 되는데 이것도 @EnableAutoConfiguration의 영향 때문 입니다.

{  
  "name": "server.port",  
  "type": "java.lang.Integer",  
  "description": "Server HTTP port.",  
  "sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties",  
  "defaultValue": 8080  
},

해당 설정은 IntelliJ IDEA 기준으로 외부 라이브러리 -> Gradle: org.springframework.boot:spring-boot-autoconfigure:${spring_boot_version} -> META-INF -> spring-configuration-metadata.json 에서 확인할 수 있습니다.

123

중복되는 빈 설정에 대한 처리 방법


protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {  
    if (!isEnabled(annotationMetadata)) {  
       return EMPTY_ENTRY;  
    }  
    AnnotationAttributes attributes = getAttributes(annotationMetadata);  
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);  
    configurations = removeDuplicates(configurations);  // 중복되는 설정 제거
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);  
    checkExcludedClasses(configurations, exclusions);  
    configurations.removeAll(exclusions);  
    configurations = getConfigurationClassFilter().filter(configurations);  
    fireAutoConfigurationImportEvents(configurations, exclusions);  
    return new AutoConfigurationEntry(configurations, exclusions);  
}

Spring Boot에서는 자동 설정할 클래스들을 먼저 불러오는데 만약 중복되는 Bean이 설정될 경우가 생기는데 이를 대비하여 처리하는 로직이 있습니다.

바로 Set을 이용하여 제외할 설정을 저장합니다. 여기서 제외할 설정들은 중복된 설정 removeDuplicates 메소드를 이용해 추려지게 됩니다. 마지막으로 이 중에서 프로젝트에 사용 되는 BeanImport할 자동 설정 대상으로 선택됩니다.

더 자세한 코드는 AutoConfigurationImportSelector.java 파일에서 확인할 수 있습니다.

YAML

위의 글에서는 Properties를 예시로 들었습니다. 하지만 저는 YAML을 더 많이 사용하고 있고 Spring Project팀에서도 YAML을 사용하고 있다고 합니다.

원래 YAML을 사용하려면 SnakeYAML 모듈을 별도로 설치해야 하지만, 이제는 Spring Boot Starter에 이 모듈이 기본으로 내장되어 있기 때문에 별도로 의존성을 추가할 필요 없이 application.propertiesapplication.yml로 이름을 바꾸면 됩니다.

만약 propertiesymal 파일이 두 개 다 존재하면 ymal 파일만 오버라이드 되어 적용이됩니다.

Ref

  1. [Spring boot] 환경 설정의 동작 원리와 애플리케이션 환경 나누기