티스토리 뷰
들어가는 말
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 해주니까... )
이 방법이 맞는 건가는 잘 모르겠다.
출처
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
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
- 전설로떠나는월가의영웅
- Generic
- meta character
- Spring
- 에픽테토스
- Async
- pecs
- 클린 아키텍처
- fsync
- jhipster
- flush
- WebSocket
- kafka 2.8.0
- 기술블로그
- PatternSyntaxException
- opensearch
- COMMIT
- 사기꾼증후군
- percolate
- completablefuture
- AWS
- Dangling
- 기술사이트
- Kafka
- 기술센싱
- 말의품격
- 개발자
- 만들면서 배우는 클린 아키텍처
- Java
- elasticsearch
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |