데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      Spring Boot 나만의 의존성 설정하기

      박제영 24.04.23
      5,715 11 0
      DEVOTEE 요약
      본 블로그는 Spring Boot의 자동설정 기능에 대해 설명하고, 사용자 정의 자동설정 파일을 만드는 방법을 안내합니다. Spring Boot의 @EnableAutoConfiguration 어노테이션을 통해 자동으로 필요한 설정을 적용하고, 사용자는 메이븐 프로젝트를 생성하여 자신의 설정 파일을 정의할 수 있습니다. 또한, 의존성을 관리하고, 프로퍼티 파일을 통해 설정 값을 가져오는 방법 등을 소개하며, Spring Boot를 통해 복잡한 설정을 간소화하고 개발자가 설정을 재정의할 수 있는 여러 옵션을 제공함을 강조합니다.

      들어가며

      Spring Boot 는 자동설정 기능을 제공하여 Spring 에서 개발자가 직접 설정하던 많은 설정 파일들 없이 손쉽고 빠르게 제품을 개발할 수 있습니다.

      이번 포스트 에서는 Spring Boot 의 자동설정에 대해 간단히 살펴보고 나만의 자동설정 파일을 만들어 보도록 하겠습니다.


      자동설정 이란

      간단한 스프링 부트 프로젝트를 만들어 보겠습니다.

      저는 인텔리 제이 Ultimate 버전을 사용 하는데요,

      굳이 Ultimate 가 아닌 무료 버전도 손쉽게 프로젝트를 만들 수 있는 방법을 제공 합니다.

      image.png

      다음> 버튼을 클릭해서 의존성을 설정해 줍니다.

      Web 만 설정해 주겠습니다.

      image.png

      프로젝트가 준비되면 애플리케이션을 실행해 줍니다.

      보시면 아무 것도 없는 빈 프로젝트이지만 톰캣도 구동되고 실제 서비스도 동작하는 것을 로그로 볼 수 있습니다.

      image.png

      Tomcat 을 구동시키는 프로그램이 없는데도 불구하고 로그파일에 Tomcat이 실행되어 있음

      우리가 설정하지 않았는데도 불구하고 Tomcat 이 구동되어 있는 것을 보면, Spring Boot 가 미리 설정을 해 놓은 것 같습니다.

      그러면 어디에 정의가 되어 있을까요?

      비밀(?) 은 @SpringBootApplication 어노테이션에 있습니다.

      쉬프트키를 누른 상태에서 해당 어노테이션을 클릭하면 세부 내용으로 들어 가는데요,

      이 안에 또 다른 어노테이션이 포함되어 있는 것을 볼 수 있습니다.

      image.png

      @SpringBootApplication 어노테이션은 아래 어노테이션들을 포함하고 있습니다.

      • @SpringBootConfiguratio

      • @EnableAutoConfiguration

      • @ComponentScan

      이중 @EnableAutoConfiguration 이름에서부터 알 수 있듯이 필요한 수많은 자동설정을 해주는 어노테이션 입니다.

      참고로, Spring Boot 에서 관리하는 자바 프로그램을 Bean 이라고 합니다.

      우리가 만들게 될 Bean 들 혹은 미리 생성해 놓은 수많은 Bean 들을 애플리케이션이 시작되면 메모리로 로드하게 되는데요..


      Spring Boot 는 Bean 을 로드 하는 과정이 두 번 있습니다.

      첫 번째는 @ComponentScan 으로 메인 애플리케이션 진입점(@SpringBootApplication이 있는 프로그램)의 패키지 내의 모든 Bean 을 로드 하게 되고

      두 번째로는 @EnableAutoCongiguration 의 Bean 들을 로드하게 됩니다.

      (만약 우리가 만든 임의의 Bean 의 이름이 두 번째 로드 한 Bean 과 로드 하게 되면 기본 설정 상태에서는 BeanDefinition Exception 이 발생하게 됩니다)


      어떤 것들을 로드 하는지 알아 보겠습니다.

      • 인텔리 제이 > 프로젝트 창 > 외부 라이브러리로 이동해서.

      • Maven: org.springframework.boot:spring-boot-auitoconfigure 로 이동합니다.

      • META-INF > Spring > org.springframework.boot.autoconfigure.AutoConfiguration.imports 로 이동하면 많은 라이브러리들을 등록하는 것을 볼 수 있습니다.

        이 목록들이 설정파일로 구성되게 됩니다.

      image.png

      우리가 설정하지 않아도 기본적으로 위의 설정들이 자동으로 구성됩니다

      META-INF > Spring > org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일에 우리가 원하는 설정만 지정해 주면 우리만의 설정파일을 만들 수 있습니다.


      나만의 의존성 만들기

      위에서 자동설정을 위한 구성파일이 무엇인지 알아봤습니다. 이제, 나만의 의존성을 만드는 방법을 진행해 보겠습니다.

      메이븐 프로젝트 생성 > 의존성 Pom파일 작성 > 테스트를 위한 Bean파일 작성 의로 의존성 구성을 해주고,

      빌드해서 jar 로 install 해주면 됩니다.

      이렇게 install 한 jar 파일은 로컬 리포지토리에 저장되고 다른 프로젝트들에서 (물론 로컬), 자동설정을 임포트 할 수 있습니다.

      image.png

      pom.xml 에 아래처럼 의존성을 추가해 줍니다.

      간단하게 spring-boot-autoconfigure, spring-boot-autoconfigure-processor 과 이 의존성들의 버전을 관리해주는 spring-boot-dependencies 를 추가했습니다.

      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
      
        <groupId>org.example</groupId>
        <artifactId>self-di</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>jar</packaging>
      
        <name>self-di</name>
        <url>http://maven.apache.org</url>
      
        <properties>
          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
      
        <dependencies>
          <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
          </dependency>
      
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
          </dependency>
      
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure-processor</artifactId>
          </dependency>
      
        </dependencies>
      
        <dependencyManagement>
          <dependencies>
            <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-dependencies</artifactId>
              <version>3.2.2</version>
              <type>pom</type>
              <scope>import</scope>
            </dependency>
          </dependencies>
        </dependencyManagement>
      </project>

      다음으로 테스트를 할 두 개의 파일을 만들어 줍니다.

      DevOcean.java

      package org.example;
      
      public class DevOcean {
          private String groupName;
          private int memberCount;
      
          public String getGroupName() {
              return groupName;
          }
      
          public void setGroupName(String groupName) {
              this.groupName = groupName;
          }
      
          public int getMemberCount() {
              return memberCount;
          }
      
          public void setMemberCount(int memberCount) {
              this.memberCount = memberCount;
          }
      
          @Override
          public String toString() {
              return "DevOcean{" +
                      "groupName='" + groupName + '\'' +
                      ", memberCount=" + memberCount +
                      '}';
          }
      }

      DevOceanConfig.java

      package org.example;
      
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      @Configuration
      public class DevOceanConfig {
      
          @Bean
          public DevOcean devOcean(){
              DevOcean devOcean = new DevOcean();
              devOcean.setGroupName("Back-End");
              devOcean.setMemberCount(4);
      
              return devOcean;
          }
      }

      그리고, resources 폴더 밑에 META-INF 를 만들고, spring.factories를 만든 다음 아래 설정파일을 추가해 줍니다.

      image.png

      이제 buile > install 을 해서 로컬 레지스터리에 등록해 줍니다.

      당연히 jar 파일이 만들어 지겠죠.

      image.png


      의존성 사용해 보기

      위에서 만든 jar 파일을 자동설정파일로 구성하는 새로운 프로젝트를 만들어 보겠습니다.

      위와 마찬가지로 maven 프로젝트를 하나 만들어 주시고, pom 파일에 dependency 를 추가해 줍니다.


      프로젝트 이름은 self-di-test로 만들었습니다.

      <dependency>
        <groupId>org.example</groupId>
        <artifactId>self-di</artifactId>
        <version>1.0-SNAPSHOT</version>
      </dependency>

      새로운 프로젝트는 단순 Maven 프로젝트이지만, 우리가 만들었던 스프링부트 의존성이 추가됐기 때문에 @SpringBootApplication 을 사용할 수 있습니다.

      프로젝트를 테스트하기 위해 두 가지 파일을 만들어 줍니다.


      DevoceanRunner.java

      @Component
      public class DevOceanRunner implements ApplicationRunner
      {
          @Autowired
          DevOcean devOcean;
      
          @Override
          public void run(ApplicationArguments args) throws Exception {
              System.out.println(devOcean.toString());
          }
      }

      웹어플리케이션을 띄우지 않고(의존성이 없기 때문에), 아래와 같이 스프링부트 메인 프로그램을 작성해 줍니다.


      App.java

      @SpringBootApplication
      public class App {
          public static void main(String[] args) {
              SpringApplication springApplication = new SpringApplication(App.class);
              springApplication.setWebApplicationType(WebApplicationType.NONE);
      
              springApplication.run(args);
          }
      } 

      프로그램을 시작하면, Bean 으로 등록한 DevOcean 객체가 정상적으로 등록되는 것을 볼 수 있습니다.

      image.png

      우리가 만든 스프링부트 자동설정과 빈이 정상적으로 등록됐음을 확인할 수 있습니다.


      제가 아까 위에서 스프링 빈이 등록되는 과정이 두 단계가 있다고 얘기 했는데요..

      1. ComponentScan 으로 우리가 만든 설정 빈등이 우선 등록 되고

      2. 자동설정으로 생성된 빈이 다음으로 등록이 됩니다.

      위에서 문제점이 하나 있는데요.. devOcean 빈은 자동설정으로 구성된 빈 입니다.

      따라서 빈 등록 순서에 따르면 2번째로 생성이 되지만 만약 동일한 이름으로 우리가 만든 빈이 있다고 하면 BeanDefinition Exception 이 발생하게 됩니다.


      아래 코드로 재현해 볼 수 있습니다.

      @SpringBootApplication
      public class App {
          public static void main(String[] args) {
              SpringApplication springApplication = new SpringApplication(App.class);
              springApplication.setWebApplicationType(WebApplicationType.NONE);
      
              springApplication.run(args);
          }
      
          //todo : ComponentScan 에서 생성되는 동일한 이름의 빈을 생성
          
          @Bean
          public DevOcean devOcean(){
              return new DevOcean();
          }
      }

      실행하면 아래처럼 오류가 발생합니다.

      ***************************
      APPLICATION FAILED TO START
      ***************************
      
      Description:
      
      The bean 'devOcean', defined in org.example.App, could not be registered. A bean with that name has already been defined in class path resource [org/example/DevOceanConfig.class] and overriding is disabled.
      
      Action:
      
      Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

      이걸 막으려면 properti 파일에서 bean재정의를 true 로 해주는 방법이 있습니다.

      그렇게 되면 동일한 이름의 빈이라 하더라도 우선순위에 의해 덮어쓰일 수 있습니다.

      spring.main.allow-bean-definition-overriding=true

      혹은, 자동설정의 빈 파일에서 아래처럼 @ConditionalOnMissingBean 을 설정해 줄 수 있습니다.

      public class DevOceanConfig {
      
          @Bean
          @ConditionalOnMissingBean
          //todo : devOcean 빈이 없을 때 빈으로 등록하는 옵션ㄴ
          public DevOcean devOcean(){
              DevOcean devOcean = new DevOcean();
              devOcean.setGroupName("Back-End");
              devOcean.setMemberCount(4);
      
              return devOcean;
          }
      }


      프로퍼티 파일에서 가져와 보자

      위에서 테스트한 예시는 빈을 만들고 해당 빈의 Getter 와 Setter 를 이용해서 약간은 복잡한 방식으로 속성 값들을 가지고 왔습니다.

      좀 더 간단하게 프로퍼티 파일(application.properties) 에 해당 값을 추가하고 이 값을 가져오게 만들 수도 있는데 아래의 파일에서 간단하게 예시를 들어 보겠습니다.

      먼저 프로퍼티 파일을 위한 파일을 자동설정으로 구성한 프로젝트에 추가해 줍니다.


      DevOceanProperties.java(추가)

      @ConfigurationProperties(prefix = "devocean")
      public class DevOceanProperties {
          private String groupName;
          private int memberCount;
      
          public String getGroupName() {
              return groupName;
          }
      
          public void setGroupName(String groupName) {
              this.groupName = groupName;
          }
      
          public int getMemberCount() {
              return memberCount;
          }
      
          public void setMemberCount(int memberCount) {
              this.memberCount = memberCount;
          }
      
          @Override
          public String toString() {
              return "DevOcean{" +
                      "groupName='" + groupName + '\'' +
                      ", memberCount=" + memberCount +
                      '}';
          }
      }

      DevOceanConfig.java (수정)

      @Configuration
      @EnableConfigurationProperties(DevOceanProperties.class)
      public class DevOceanConfig {
      
          @Bean
          @ConditionalOnMissingBean(DevOcean.class)
          public DevOcean devOcean(DevOceanProperties properties){
              DevOcean devOcean = new DevOcean();
              devOcean.setGroupName(properties.getGroupName());
              devOcean.setMemberCount(properties.getMemberCount());
      
              return devOcean;
          }
      }

      pom 파일에 아래 의존성을 추가해 줍니다.

          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
          </dependency>

      이제 build > install 을 해 줍니다.

      자, 이제 의존성을 주입받는 di-self-test 로 돌아와서, application.properties 파일에 아래처럼 추가해 줄 수 있습니다.

      spring.main.allow-bean-definition-overriding=true
      devocean.group-name=JAVABACKEND
      devocean.member-count=200

      실행하면 아래처럼 정상적으로 설정파일에 등록한 값을 가져오는 것을 볼 수 있습니다.

      /Users/jaeyoungpark/Library/Java/JavaVirtualMachines/corretto-17.0.10/Contents/Home/bin/java -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:/Users/jaeyoungpark/Applications/IntelliJ IDEA Ultimate.app/Contents/lib/idea_rt.jar=63327:/Users/jaeyoungpark/Applications/IntelliJ IDEA Ultimate.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/jaeyoungpark/Desktop/start_spring/self-di-test/target/classes:/Users/jaeyoungpark/.m2/repository/org/example/self-di/1.0-SNAPSHOT/self-di-1.0-SNAPSHOT.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/3.2.2/spring-boot-autoconfigure-3.2.2.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/boot/spring-boot/3.2.2/spring-boot-3.2.2.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/spring-core/6.1.3/spring-core-6.1.3.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/spring-jcl/6.1.3/spring-jcl-6.1.3.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/spring-context/6.1.3/spring-context-6.1.3.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/spring-aop/6.1.3/spring-aop-6.1.3.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/spring-beans/6.1.3/spring-beans-6.1.3.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/spring-expression/6.1.3/spring-expression-6.1.3.jar:/Users/jaeyoungpark/.m2/repository/io/micrometer/micrometer-observation/1.12.2/micrometer-observation-1.12.2.jar:/Users/jaeyoungpark/.m2/repository/io/micrometer/micrometer-commons/1.12.2/micrometer-commons-1.12.2.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/boot/spring-boot-autoconfigure-processor/3.2.2/spring-boot-autoconfigure-processor-3.2.2.jar:/Users/jaeyoungpark/.m2/repository/org/springframework/boot/spring-boot-configuration-processor/3.2.2/spring-boot-configuration-processor-3.2.2.jar org.example.App
      
        .   ____          _            __ _ _
       /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
      ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
       \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
        '  |____| .__|_| |_|_| |_\__, | / / / /
       =========|_|==============|___/=/_/_/_/
       :: Spring Boot ::                (v3.2.2)
      
      [2024-03-17 08:36:51.742] - 25330 정보 [main] --- org.example.App: Starting App using Java 17.0.10 with PID 25330 (/Users/jaeyoungpark/Desktop/start_spring/self-di-test/target/classes started by jaeyoungpark in /Users/jaeyoungpark/Desktop/start_spring/self-di-test)
      [2024-03-17 08:36:51.753] - 25330 정보 [main] --- org.example.App: No active profile set, falling back to 1 default profile: "default"
      [2024-03-17 08:36:51.961] - 25330 정보 [main] --- org.example.App: Started App in 0.349 seconds (process running for 0.506)
      DevOcean{groupName='JAVABACKEND', memberCount=200}


      마치며

      스프링 부트의 3가지 주요 내용인 DI(Dipendency Injection), 자동설정, 추상화가 중에서 자동설정과 DI에 대해서 간단히 알아 봤습니다.

      스프링 부트는 이러한 복잡한 설정 등을 최대한 자동화 해주고 또한 개발자가 설정을 재 정의할 수 있는 아주 많은 옵션을 제공해 주고 있습니다.


      참고

      프로젝트 구성을 간단하게 정리해 봤습니다.


      self-di 프로젝트

      image.png


      self-di-test 프로젝트

      image.png

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      박제영 님의 최신 블로그

      더보기