본문 바로가기
자바,스프링 - Java,Spring Framework

스프링부트 라이브러리 만들기, spring boot auto configuration, 공통 exception 처리 라이브러리 만들기

by devscb 2023. 10. 19.
반응형

스프링부트 라이브러리 만들기, spring boot auto configuration, 공통 exception 처리 라이브러리 만들기

배경

최근에, 여러 spring boot 프로젝트를 개발하는 대형프로젝트를 진행하고 있습니다.
그런데, 각 spring boot에서 공통적으로 코드를 사용하는 부분이 있습니다.
예를 들어, exception 처리와 같은 부분입니다.
controller쪽에서 exception을 발생시키면 아래와 같은 json 결과를 http response로 보내고,
http status 는 500에러를 발생하고자 하였습니다.
{"message":"ERROR_INTERNAL","result":null}

이를 처리하기 위해서는 스프링 부트 프로젝트에 spring boot aop를 적용하여 처리하는 식으로 개발이 가능합니다.
그런데, 이 코드를 전 프로젝트에 대해 각각 적용하면 코드가 너무 많습니다.
프로젝트가 한 두개면 몰라도, 10개가 넘는 프로젝트에 적용을 해야하니 복사+붙여넣기는 너무 비효율적입니다.

그렇다면 좀 더 효율적인 방법은 없을까?
라고 생각하여 spring boot의 다른 라이브러리들을 살펴보게 되었고, 해결책을 찾아냈습니다.
그 것이 바로 spring boot auto configuration입니다.

spring boot auto configuration이란?

spring boot auto configuration이란 간단히 설명하자면,
해당 기술을 쓴 라이브러리를 import하면 프로젝트에서 자동설정이 된다. 라고 볼 수 있습니다.
즉, import한 프로젝트에서 별도의 실행하는 코딩없이 라이브러리 안의 코드를 자동으로 실행해 줍니다.

단순히 libarary를 import하면, 자동으로 실행이 되는 점이 개발 생산성을 크게 향상시켜줍니다.

이 글에서는 이런 spring library를 마들고 공통라이브러리를 활용하는 부분을 소개합니다.

공통 exception 처리 라이브러리 만들기

IDE : eclipse기반으로 설명합니다.

1) 먼저, 아래와 같이 maven 프로젝트를 만들어 줍니다.

 

 

 

 

 

 

2) pom.xml에 지원할 jdk 버전, encoding, maven plugin 버전을 명시해줍니다.
해당 내용들을 적지 않으면 ecslipe상에서 Unknown이라는 문제를 problems 에서 확인할 수 있습니다.
각각의 개발환경에 따라 세팅해주세요.
jdk버전과 maven version은 각자의 환경에 맞게 버전을 변경해주세요.

<properties>
 <targetJdk>1.8</targetJdk>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <maven-jar-plugin.version>2.6</maven-jar-plugin.version>
</properties>

3) 그다음, 아래와 같이 dependency를 추가해줍니다.

<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.7.10</version>
</parent>
<dependencies>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-autoconfigure</artifactId>
 </dependency>
</dependencies>

2,3 을 진행하면 pom.xml의 전체 내용은 아래와 같습니다.

<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>com.devscb</groupId>
  <artifactId>springboot-lib-test</artifactId>
  <version>0.0.1-SNAPSHOT</version>

 <properties>
 <targetJdk>1.8</targetJdk>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
</properties>
<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.7.10</version>
</parent>
<dependencies>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-autoconfigure</artifactId>
 </dependency>
</dependencies>
</project>

4) AutoConfig를 실행할 초기화 클래스를 아래와 같이 작성해줍니다.
src/main/java/com/devscb/AutoConfig.class 파일을 생성합니다.

package com.devscb;

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;


@AutoConfiguration
public class AutoConfig {
 @Bean
 public ExceptionHandleControllerAdvice errorHandleControllerAdvice() {
  return new ExceptionHandleControllerAdvice();
 }
}

ExceptionHandleControllerAdvice 클래스에서는 우리가 exception을 처리할 내용들을 작성합니다.
이 내용은 @AutoConfiguration이 붙은 class에 정의된 @Bean들을 초기화하겠다는 뜻입니다.

5) ExceptionHandleControllerAdvice 를 작성해줍니다.
src/main/java/com/devscb/ExceptionHandleControllerAdvice.class 파일을 생성합니다.


package com.devscb;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class ExceptionHandleControllerAdvice {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Map<String, Object>> handle(final Exception e) {
     Map<String, Object> result = new HashMap<String, Object>(){{
      put("message", "ERROR_INTERNAL");
      put("result", e.getMessage());
     }};

     return new ResponseEntity<Map<String, Object>>(result, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

이 부분은 단독 spring boot 에서도 잘 쓰이는 부분입니다.
먼저, @ControllerAdvice를 사용하면, controller에 대해 전역적으로 적용되어 로직을 실행시킬 수 있습니다.
@ExceptionHandler는 exception이 발생했을때, 처리할 메소드를 정의할 수 있습니다.
자세한 내용은 기회가 될 때, 추후에 다시 다뤄보겠습니다.

6) 다음으로, src/main/resource/META-INF에 spring.factories 파일을 만들고,
아래와 같은 내용으로 작성해줍니다.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
 com.devscb.AutoConfig

7) 앞선 예제를 잘 만들었다면, 폴더구조는 아래와 같이 되어 있을것입니다.
(test 폴더는 자동으로 생성된것으로, 아무런 내용 없어도 무방합니다)

.
│ pom.xml
└─src
└─main
├─java
│ └─com
│ └─devscb
│ AutoConfig.java
│ ExceptionHandleControllerAdvice.java

└─resources
└─META-INF
spring.factories

공통 라이브러리 활용하기

앞선 공통라이브러리를 만들고 나서 각 프로젝트에서는 이 라이브러리를 어떻게 활용할 수 있는지 알아보겠습니다.

1) 아래와 같이 maven 프로젝트를 만들어 줍니다.

2) pom.xml 전체 내용을 아래와 같이 수정해줍니다.

<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>com.devscb</groupId>
  <artifactId>springboot-lib-test</artifactId>
  <version>0.0.1-SNAPSHOT</version>
 <properties>
  <targetJdk>1.8</targetJdk>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
 </properties>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.7.10</version>
 </parent>
 <dependencies>
 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 </dependencies>
</project>

3) 다음으로, Application.java 파일을 만들고,
아래와 같은 내용으로 작성해줍니다.

package com.devscb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

4) 다음으로, Controller.java 파일을 아래와 같이 작성해줍니다.
test1은 정상적인 요청이 될것이고,
test2는 exception이 발생하는 케이스로, auto configuration 이 잘 동작하는지 확인해볼 것입니다.

package com.devscb;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping
public class Controller {

 @RequestMapping("/test1")
    public Map<String, Object> test1() throws Exception{
  Map<String, Object> result = new HashMap<String, Object>(){{
      put("message", "sucess");
      put("result", null);
     }};
     return result;
    }


 @RequestMapping("/test2")
    public Map<String, Object> test2() throws Exception{
  throw new Exception("error");
    }
}

파일구조는 아래와 같습니다.
.
│ pom.xml
└─src
└─main
└─java
└─ com
└─devscb
Application.java
Controller.java

5) 그 다음 아까 만든 공통 라이브러리를 import해보겠습니다.
먼저, 프로젝트 우측클릭 후 build path > configure build path 를 눌러줍니다.

그 다음, projects 탭에서 Add 버튼을 누르고, 공통라이브러리 프로젝트를 선택해줍니다.

마지막으로, order and export 탭에서 공통라이브러리 프로젝트를 체크한 뒤, apply and close 버튼을 누릅니다.

6) 모든 설정이 완료된 후,
Application.java 를 실행해줍니다

7) 웹 브라우저에서 아래와 같이 url을 입력하여 결과를 보면,
exception handler가 잘 적용된것을 알 수 있습니다.
(test2에서 autoconfiguration에 설정한 exception error메시지를 보냄.)
http://localhost:8080/test1
http://localhost:8080/test2

총평

auto configuration은 마치 다른 프로그램들의 플러그인(plugin)과 비슷한 개념같다는 생각이 들었습니다.
이 부분을 공부하면서 스프링 부트가 정말 성숙한 프레임워크라고 생각이 들었고,
라이브러리를 만들 때 고민해야하는 부분을 잘 설계한거 같다는 생각이 들었습니다.
그나마 한가지 아쉬운 점을 꼽자면, 명칭을 이렇게 짓는게 맞을까? 란 부분이 있을거 같습니다.
라이브러리를 설계하는데 나는 이런 기능을 원하는데, 뭐라고 쳐야하지 라는 고민을 했었습니다.
딱히 키워드가 생각이 안나서 비슷한 기능을 하는 프로젝트를 찾아보고, 어떻게 구현했는지 소스를 분석하면서 알아내게 되었습니다.
키워드를 뭐라고 해야할지 말씀주신다면 키워드를 추가하여 이 글을 찾는 분들께 도움이 되었으면 합니다.

#스프링부트,#스프링,#라이브러리,#autoconfiguration,#auto,#configuration,#springboot,#spring,#library,#exception,#advice

 

https://devscb.com/post/183

 

Creating a Spring Boot library, spring boot auto configuration, creating a common exception handling library

Creating a spring boot library, spring boot auto configuration, creating a common exception handling library backgroundRecently, I have been working on a large project to develop several spring boot p

devscb.com

 

728x90
반응형

댓글