Nick Dev

[Kotlin] @Transactional 붙이는데 open을 하라고?? 본문

Kotlin

[Kotlin] @Transactional 붙이는데 open을 하라고??

Nick99 2025. 1. 12. 10:40
반응형

코틀린 공부를 하다가 서비스 계층에서 @Transactional을 붙이니깐 빨간 밑줄이 뜨며 클래스와 함수를 open 해야 한다고 뜬다. 왜 그럴까??

⭐️ 바로 @Transactional의 동작 방식 때문이다! ⭐️

@Transactional의 동작 방식

  • Spring은 이 어노테이션이 붙은 클래스나 메서드에 대해서 Spring AOP를 통해서 프록시를 생성한다

  • Spring AOP는 원본 클래스를 상속받아서 메서드 앞 뒤로 트랜잭션 관련 로직을 추가한다

  • 하지만 코틀린은 기본적으로 모든 클래스와 메서드가 final이다 (자바와 반대)

    • 자바는 기본적으로 모두 상속 가능한 상태고 명시적으로 final 키워드를 붙여서 막는다
    • final 클래스(메서드)는 상속(오버라이드)가 불가능하다
  • 그렇기 때문에 Intellij가 "야 @Transactional 쓸꺼면 클래스랑 함수 상속/오버라이드 할 수 있게 열어" 라고 알려주는거다

  • 이렇게 코틀린에서 상속 가능하게 해주는 키워드가 바로 open인 것이다

@Service  
open class UserService(  
    private val userRepository: UserRepository,  
) {  

    @Transactional  
    open fun saveUser(request: UserCreateRequest) {  
        val newUser = User(  
            name = request.name,  
            age = request.age,  
        )  
        userRepository.save(newUser)  
    }
}

⁉️ 그럼 코프링 쓰면 @Transactional 겁나 많이 쓰는데 전부 다 open 키워드 붙여야 돼????

  • 이걸 가만히 냅두면 개발자가 아니지!
  • ⭐️ plugin을 통해서 자동으로 open을 적용해줄 수 있다!!! ⭐️

✅ 플러그인으로 open 자동 적용하기!

build.gralde에 플러그인 추가하기

plugins {    
    ...

    id 'org.jetbrains.kotlin.plugin.spring' version '1.6.21' 
}
  • 이렇게 플러그인을 적용하면 open 키워드를 붙이지 않아도 자동으로 처리해준다

    • 이 플러그인은 Spring 관련 어노테이션들에 대해 미리 설정된 all-open 플러그인이다

    • 만약 Spring 어노테이션 말고 커스텀 어노테이션에 대해서 open 설정을 해야한다면 kotlin.plugin.allopen으로 수정해줘야 한다

  • 아까 위의 코드는 이제 아래와 같이 바뀐다

@Service  
class UserService(  
    private val userRepository: UserRepository,  
) {  

    @Transactional  
    fun saveUser(request: UserCreateRequest) {  
        val newUser = User(  
            name = request.name,  
            age = request.age,  
        )  
        userRepository.save(newUser)  
    }
}
  • @Transactional 말고도 다른 어노테이션들도 open 키워드가 필요하다!! 어떤 것들이 있을까??

자동 처리되는 어노테이션들

  • @Component

  • @Async

  • @Transcational

  • @Cacheable

  • @SpringBootTest

  • ...

  • 대부분 프록시 기반으로 동작

그럼 여기서 또 드는 작은 의문... 플러그인이 뭘 어떻게 해주길래 자동으로 쑉쑉 open 키워드를 넣어주는 걸까??

생각보다 간단하다!!!

✅ 플러그인의 동작 방식

컴파일 할 때, 지정된 어노테이션을 발견하면 해당 요소를 수정해준다!

  • 컴파일 시점에 바이트 코드를 조작해서 open이 필요한 부분에 알아서 넣어준다!!

  • 예를 들어 컴파일 하다가 @Cacheable을 만나면 해당 함수 앞에 open을 붙여준다

내가 작성한 코드

class MyService { 
    @Cacheable 
    fun doSomething() {} 
}

컴파일 후 코드(최종 바이트 코드)

  • 물론 바이트 코드이기 때문에 아래와 같이 보이진 않지만 이렇게 작성한 거처럼 컴파일을 했을 것!!
    open class MyService { 
      @Cacheable 
      open fun doSomething() {} 
    }
반응형