- Spring Boot AutoConfiguration 간단 모듈 만들어보기2023년 09월 24일
- 알쓸개잡
- 작성자
- 2023.09.24.:12
Spring Boot AutoConfiguration은 여러 디펜던시 들의 Configuration을 자동으로 수행하여 복잡한 Configuration 구성 없이 필요한 빈을 자동으로 주입 받을 수 있도록 도와주는 기능이다. 이번 포스팅에서는 Spring Boot AutoConfiguration이 동작하는 간단한 예제 코드를 작성해 보겠다.
AutoConfiguration class
AutoConfiguration을 구현하는 클래스는 @AutoConfiguration 어노테이션이 지정 된다. 또한 여러 @Conditional 어노테이션을 통해서 AutoConfiguration이 적용되어야 하는 필터를 설정할 수 있다. 일반적으로 AutoConfiguration 클래스는 @ConditionalOnClass 및 @ConditionalOnMissingBean 어노테이션이 많이 사용된다. AutoConfiguration에 관한 Conditional 어노테이션이 많이 있는데 spring boot autoconfigure condition 페이지를 참고하면 좋을 것 같다.
샘플 코드
샘플 코드에 대해서 간단히 설명하면 AutoConfiguration을 통해서 자동으로 주입되는 빈은 두 개의 숫자와 BiFunctional 람다 함수를 입력 받아 두 개의 숫자를 람다 함수에 전달하여 람다 함수가 수행한 결과를 리턴하는 메소드를 가진 클래스이다. 이름은 calculator 이다.
AutoConfiguration이 동작하는 조건은 다음과 같다.
- calculator.use-auto-configure=true
- Calculator.class 클래스가 클래스 패스에 있어야 함
필요한 모듈은 아래와 같다.
- calculator: 빈으로 생성될 대상 클래스를 가지고 있는 모듈
- calculator-autoconfigure: AutoConfiguration을 수행할 모듈
- calculator-starter: calculator-autoconfigure, calculator를 디펜던시로 갖는 starter 모듈
- calculatorapp: calculator-starter를 디펜더시로 갖는 테스트 애플리케이션
편의상 멀티 모듈 프로젝트로 작성하였다.
root pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>simple-starter</artifactId> <version>0.0.1</version> <packaging>pom</packaging> <name>simple-starter</name> <description>simple-starter</description> <modules> <module>calculator</module> <module>calculator-autoconfigure</module> <module>calculator-starter</module> <module>calculatorApp</module> </modules> </project>
Calculator 모듈
calculator는 실제 동작을 수행하는 클래스를 갖는 모듈이다.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <groupId>com.example</groupId> <artifactId>calculator</artifactId> <version>0.0.1</version> </project>
package com.example.calculator; import java.util.function.BiFunction; public class Calculator { private final String resultPrefix; public Calculator(String resultPrefix) { this.resultPrefix = resultPrefix; } public String calculate(int x, int y, BiFunction<Integer, Integer, Integer> what) { return what.andThen((result) -> resultPrefix + " " + result).apply(x, y); } }
calculate 메소드에서 두 숫자의 연산 결과 앞에 resultPrefix를 붙여 String 타입의 결과를 리턴하도록 하였다.
Calculator 생성자의 resultPrefix 파라미터는 calculator-autoconfigure에서 Calculator를 빈으로 주입시 calculator.result-prefix 속성에 지정된 값을 넘겨준다.
calculator-autoconfigure 모듈
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>calculator-autoconfigure</artifactId> <version>0.0.1</version> <name>calculator-autoconfigure</name> <description>calculator-autoconfigure</description> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- properties 설정을 자동으로 주입받기 위함 META-INF/spring-configuration-metadata.json 에 기록됨 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!-- auto configuration의 conditional 필터 정보를 META-INF/spring-autoconfigure-metadata.properties 에 작성하기 위함 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- auto configuration을 생성하기 위함 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <!-- Calculator 클래스를 빈으로 생성하기 위함 --> <!-- starter를 만들어서 배포하는 경우에는 starter에서 종속성을 갖도록 optional을 true로 지정한다. --> <dependency> <groupId>com.example</groupId> <artifactId>calculator</artifactId> <version>${project.version}</version> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> </project>
CalculatorProperties.java
package com.example.calculator.autoconfigure.property; import lombok.Getter; import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "calculator") @Getter @Setter public class CalculatorProperties { private boolean useAutoConfigure; private String resultPrefix; }
calculator.use-auto-configure, calculator.result-prefix 설정 값을 주입받는다.
CalculatorAutoConfiguration.java
package com.example.calculator.autoconfigure.configuration; import com.example.calculator.Calculator; import com.example.calculator.autoconfigure.property.CalculatorProperties; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass({Calculator.class}) @EnableConfigurationProperties(CalculatorProperties.class) @ConditionalOnProperty(prefix = "calculator", name = "use-auto-configure", havingValue = "true") public class CalculatorAutoConfiguration { @ConditionalOnMissingBean(Calculator.class) @Bean public Calculator calculator(CalculatorProperties calculatorProperties) { return new Calculator(calculatorProperties.getResultPrefix()); } }
ConditionalOnClass 어노테이션에 의해서 Calculator.class 가 클래스 패스에 있어야 한다. 즉, com.example:calculaor 디펜던시가 있어야 한다. ConditionalOnProperty 어노테이션에 의해서 calculator.use-auto-configure=true 인 경우 에만 AutoConfiguration이 동작한다.
AutoConfiguration.imports
resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일에 AutoConfiguration을 수행하는 클래스 파일 경로를 기록해야 한다. Spring Boot 에서는 이 파일에 있는 경로의 AutoConfiguration 파일을 자동 설정 대상으로 한다.
com.example.calculator.autoconfigure.configuration.CalculatorAutoConfiguration
calculator-starter 모듈
pom.xml
starter는 종속성만 가지고 있기 때문에 pom.xml만 정의한다.
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>calculator-starter</artifactId> <version>0.0.1</version> <name>calculator-starter</name> <description>calculator-starter</description> <dependencies> <dependency> <groupId>com.example</groupId> <artifactId>calculator-autoconfigure</artifactId> <version>${project.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>calculator</artifactId> <version>${project.version}</version> <scope>compile</scope> </dependency> </dependencies> </project>
calculatorApp 애플리케이션
AutoConfiguration 동작을 테스트 해보기 위한 애플리케이션이다.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>calculatorApp</artifactId> <version>0.0.1-SNAPSHOT</version> <name>calculatorApp</name> <description>calculatorApp</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.example</groupId> <artifactId>calculator-starter</artifactId> <version>0.0.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
application.yml
calculator: use-auto-configure: true result-prefix: 'result is'
calculator.use-auto-configure: false 를 셋팅하면 AutoConfiguration이 동작하지 않으므로 아래 CalculatorAppApplication.java 코드에서 Calculator calculator 는 자동 주입되지 않는다.
CalculatorAppApplication.java
package com.example.calculatorapp; import com.example.calculator.Calculator; import lombok.RequiredArgsConstructor; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @RequiredArgsConstructor public class CalculatorAppApplication implements CommandLineRunner { //calculator-starter를 통해 배포된 calculator-autoconfigure에 의해서 자동 주입된다. private final Calculator calculator; public static void main(String[] args) { SpringApplication.run(CalculatorAppApplication.class, args); } @Override public void run(String... args) throws Exception { //calculator.result-prefix + 더하기 연산 수행한 결과 String result = calculator.calculate(1, 2, Integer::sum); System.out.println(result); //곱하기 연산 수행 결과 result = calculator.calculate(2, 3, (x, y) -> x * y); System.out.println(result); //곱하기 연산 수행 결과 result = calculator.calculate(4, 5, (x, y) -> x * y); System.out.println(result); } }
빌드 및 실행
$>./mvnw clean compile ... [INFO] Reactor Summary: [INFO] [INFO] calculator 0.0.1 ................................... SUCCESS [ 0.322 s] [INFO] calculator-autoconfigure 0.0.1 ..................... SUCCESS [ 0.411 s] [INFO] calculator-starter 0.0.1 ........................... SUCCESS [ 0.011 s] [INFO] calculatorApp 0.0.1-SNAPSHOT ....................... SUCCESS [ 0.184 s] [INFO] simple-starter 0.0.1 ............................... SUCCESS [ 0.001 s] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS $>./mvnw install ... $>./mvnw spring-boot:run -pl calculatorApp .... result is 3 result is 6 result is 20
정상적으로 Calculator 인스턴스가 주입 되어 수행되는 것을 확인할 수 있다. 또한 calculator.result-prefix 설정도 적용된 것을 알 수 있다. 간단하게나마 spring boot auto configuration 샘플 코드를 작성해 보았다.
관련 코드는
https://gitlab.com/blog4031530/spring-simple-starter 에 있다.
blog / spring-simple-starter · GitLab
GitLab.com
gitlab.com
'스프링부트' 카테고리의 다른 글
application events and listeners (0) 2023.10.02 spring boot JMS activemq connection factory (0) 2023.09.28 spring boot actuator health endpoints delay check (0) 2023.09.22 spring boot websocket (웹소켓) (0) 2023.09.20 spring boot application startup tracking (0) 2023.09.17 다음글이전글이전 글이 없습니다.댓글