티스토리 뷰

개발관련/spring

@Lookup

xephysis 2021. 5. 15. 20:05

들어가는 말

spring core reference 문서 뒤적거리다가 처음 보는 어노테이션(개념)이 있어서 궁금해서 정리

 

간단하게는

@Lookup 어노테이션이 달린 메서드가 호출될 때 스프링이 bean을 찾아서 리턴해준다.

 

어디에 쓰는지

singleton bean에게 prototype scope인 bean을 주입할 때 사용한다

디펜던시를 순차적절차적으로 주입할 때 사용한다

... 고 한다

 

singleton bean에게 prototype scope인 bean을 주입할 때 사용한다

baeldung에 예제 비슷한 게 있어서 돌려봄

 

@Service
class CommonService {
    @Lookup
    fun getNotification(): Notification? {
        return null
    }
}
@Scope("prototype")
@Component
class Notification {
    init {
        println("Notification created")
    }
}
@SpringBootTest
class LookupTest {

    @Autowired
    lateinit var context: ApplicationContext

    @Test
    fun `compare lookup instance`() {
        val service = context.getBean("commonService") as CommonService
        val schoolNotification1 = service.getNotification()
        val schoolNotification2 = service.getNotification()
        assertThat(schoolNotification1).isNotEqualTo(schoolNotification2)
        println(schoolNotification1)
        println(schoolNotification2)
    }
}

예상했던 것처럼 null을 리턴하는 건 아니고, spring에서 매번 prototype bean을 생성해서 돌려준다.

Notification created
Notification created
me.xep.lookupdemo.school.SchoolNotification@11b5f4e2
me.xep.lookupdemo.school.SchoolNotification@6bcae9

그냥 넘어가기 섭섭하니까 prototype scope을 기본으로 돌려놓고 테스트 (singleton)

 

역시나 에러 발생 (테스트 코드 자체가 이걸 의도한 게 아니었으니)

scope와 무관하게 spring 이 type based로 candidate를 찾아서 돌려준다 (bean을)

java.lang.AssertionError: 
Expecting:
 <me.xep.lookupdemo.domain.Notification@11f23203>
not to be equal to:
 <me.xep.lookupdemo.domain.Notification@11f23203>

그래서 이걸 왜 쓰는 거지

역시 stackoverflow 에는 답변이 있다.

https://stackoverflow.com/a/55524224

 

Why do we need @Lookup, whats wrong with scope=prototype?

I'm studying spring beans and came across @Lookup, it says: If we happen to decide to have a prototype Spring bean, then we are almost immediately faced with the problem of how will our single...

stackoverflow.com

scope 이 prototype 인 bean 들을 주입받아 prototype으로서 사용하고 싶을 때 쓴다.

만약에 위에 있는 예제 중 CommonService에 constructor 나 setter 방식으로 Notification이라는 bean을 주입받으면 어떻게 될까?

 

당연히 잘 주입받는다. 한 번만, 고정적으로

 

이상하지 않나? prototype scope는 매번 필요할 때마다 application context 가 새로 생성해 주는 걸 텐데

한 번만, 고정적으로 받아서 쓰는 건 이상하다.

 

그래서 @Lookup을 쓰는 것 같다.

(매번 getBean을 명시적으로 호출해도 되긴 할 텐데 로직에서 명시적으로 spring application context까지 들고 와서 getBean 하는 건 좀 거시기해 보인다.)

 

javadoc을 봐도 첫 문장부터 그렇다고 말하고 있다.

An annotation that indicates 'lookup' methods, to be overridden by the container to redirect them back to the BeanFactory for a getBean call. This is essentially an annotation-based version of the XML lookup-method attribute, resulting in the same runtime arrangement.

 

그 외 - nullable 말고 다른 방법이 없을까

@Lookup
fun getNotification(): Notification? {
    return null
}
@Lookup
fun getNotification(): Notification {
    return Notification()
}

 

조금 석연치 않은 부분이 있어서 보강한다.

kotlin으로 코드를 짜다 보니 return type을 nullable으로 명시해 두었었다. 

return null 대신 두 번째 코드 블록 같이 선언해 두는 것도 가능하긴 한데, 위험해 보인다.

(나중에 코드를 보는 사람은 이 코드를 바로 이해하지 못하고 저 안에다가 뭔가 구현할 수도 있어 보인다.)

 

만약에 Notification type의 bean을 못 찾으면 어떻게 동작할까?

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'me.xep.lookupdemo.domain.Notification' available

깔끔하게 터진다. 

nullable로 리턴할 이유가 전혀 없어 보인다.

기본 동작(선언해 놓은 부분을 타는 경우)은 없다.

 

다른 방법이 있을 것 같다.

@Service
abstract class CommonService {
    @Lookup
    abstract fun getNotification(): Notification
}

getNotification 메서드 시그네쳐 이외에 구현 부분은 사용하지 않으니 abstract로 풀어버리는 방법이다.

동작은 잘한다. (어차피 spring 이 proxying 해주니까... )

이 방법이 맞는 건가는 잘 모르겠다.

 

 

 

 

출처

https://docs.spring.io/spring-framework/docs/5.3.5/reference/html/core.html#beans-factory-lookup-method-injection

 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io

https://www.baeldung.com/spring-lookup

 

@Lookup Annotation in Spring | Baeldung

Learn how to effectively use the @Lookup annotation in Spring for procedural injection.

www.baeldung.com

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Lookup.html

 

Lookup (Spring Framework 5.3.7 API)

An annotation that indicates 'lookup' methods, to be overridden by the container to redirect them back to the BeanFactory for a getBean call. This is essentially an annotation-based version of the XML lookup-method attribute, resulting in the same runtime

docs.spring.io

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함