Groovy Console을 통한 스프링부트 검증

Kyu Yeon 'rebel' Lee·2022년 11월 26일
0

개요

  • 개발하다가 Service, Config, Bean관련해서 올리고 또 올리는게 너무 빡침
  • 수정된 코드를 확인하는데 30초 - 1분 30초가 걸린다는건 모욕적
  • 나는 바로 확인하고 싶다.

시도

스프링 분석

  • 모든 서비스는 main으로 시작한다. 그렇다는건 스프링도 뭔가가 있을것.
    찾아보니 SpringApplication.main 이 있었다.
  • 여기서 보니까 내 프로젝트의 스프링 메인 클래스를 참조해서 인스턴스를 만들어서 종료시까지 블록킹 해주는 듯 하다.
  • 그렇다면 내가 할일은...
    • 스프링 실행
    • 스프링 실행함과 동시에 스프링 컨텍스트를 건져서 덮어쓰고 읽고 실행하고 해보기

코드

import 내프로젝트.메인Application
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
import org.springframework.context.ConfigurableApplicationContext

import javax.swing.Spring
import java.util.concurrent.ConcurrentHashMap

def MyService = 메인Application.class

// 끔찍하지만, 스프링 콘솔 특성상 어쩔수 없다!
// 같은 스크립트를 무한 실행해도 값을 덮어쓰지 않도록 조치하자.
try {GlobalSpringApplication = GlobalSpringApplication}
catch (Exception ignored){GlobalSpringApplication = null}
if (GlobalSpringApplication == null) GlobalSpringApplication = new SpringApplication(MyService)

// 스프링을 스레드에서 돌리기 위한 Runnable
// 이거로 스레드를 시작하면, 시작 함수 실행시 블로킹 되지 않는다.
// 매니지먼트는 알바 없다. 스캐폴딩에 그런게 무슨 소용인가?
class REPLSpringServerRunnable implements Runnable {
    ConfigurableApplicationContext SpringContext
    SpringApplication GlobalSpringApplication

    REPLSpringServerRunnable(def GlobalSpringApplication) {
        this.GlobalSpringApplication = GlobalSpringApplication as SpringApplication
    }

    void run() {
        this.SpringContext = GlobalSpringApplication.run()
    }
}

// 스프링 스레드 작업 시작
try {CurrentSpringApplication = CurrentSpringApplication}
catch (Exception ignored){CurrentSpringApplication = null}
if (CurrentSpringApplication == null) {
    CurrentSpringApplication = new REPLSpringServerRunnable(GlobalSpringApplication)
    new Thread(CurrentSpringApplication).start();
}

// 모든 빈을 불러온다!
def SpringApplicationContext = CurrentSpringApplication.springContext as AnnotationConfigServletWebServerApplicationContext
println ("=========================")
println ("Here is all the beans we have")
println ("------------------------")
for (final a in SpringApplicationContext.getBeanFactory().beanDefinitionMap) {
    println (a.Key)
}
println ("=========================")

결과

주르륵 다나온다.

...
commentResource
org.springframework.boot.autoconfigure.domain.EntityScanPackages
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$DefaultTemplateResolverConfiguration
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration
springSecurityFilterChain
enableGlobalAuthenticationAutowiredConfigurer
servletWebServerFactoryCustomizer
mvcUrlPathHelper
...
  • 지금 뜯어보는게 전에 예시 코드용으로 만든 게시판 프로젝트인데, 이 프로젝트에 있는 모든 댓글들을 따보자.

  • 다 나온다.
    이러면 일일히 curl날려서 검증할 필요가 없다. 왜냐면 날린거랑 이거랑 다른게 없기 때문이다.

  • 스프링에서 가장 귀찮은 API및 메서드 검증을 미리 이렇게 하고 추후에 테스트로 박아넣으면 스프링도 꽤나 나쁘지 않다.

  • 여기서 확인할 수 있는건, 컨트롤러, 서비스, 설정 등 모든 스프링 컴포넌트들이 Bean 취급 된다는 것.

  • 사실 뭔가 다 분리되어있고 복잡한 모듈로 되어있는것처럼 보이지만, 사실 Bean이라는 핵심 아래에 여러 큰 베이스가 되는 클래스가 트리처럼 퍼지는 구조로 되어있다.

  • 대부분이 자동화되어서 처리되는 구조라 퍽하고 터지거나 하지도 않은 일이 터지는 일이 잦게 되어있음
    (특히 망할 Reflection을 통한 Method Proxy가 떡칠되어있는거 보고 이걸 디버깅 할 생각을 하지 않는게 좋다고 생각되었다.)

제한

  • Bean을 등록하려고 하면 자꾸 재시작하려고 해서 터진다. 별도의 메서드 오버라이딩이나 에이전트를 이용한 뭔가를 꾸미면 되는 걸까
  • Groovy Metaclass를 무시한다. 애초부터 Java로 만들어진 앱이다 보니 MetaClass의 InvokeMethod는 호출하지 않는다고 들은 듯 하다. 추후에 검증해볼 것.

생각

  • 스프링용 테스트 데이터를 어떻게 하면더 쉽게 테스트 데이터를 만들 수 있을까
  • 왜 이렇게 해야하는지부터 알아내자. 스프링이 쓰기 싫을정도로 귀찮다면 뭔가 다른 사람도 해결책을 냈을 듯 하다.

0개의 댓글