티스토리 뷰
들어가는 말
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
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://www.baeldung.com/spring-lookup
- Total
- Today
- Yesterday
- 만들면서 배우는 클린 아키텍처
- Async
- flush
- Java
- PatternSyntaxException
- Dangling
- WebSocket
- 사기꾼증후군
- 기술센싱
- COMMIT
- 말의품격
- 기술블로그
- opensearch
- percolate
- 개발자
- Generic
- kafka 2.8.0
- 전설로떠나는월가의영웅
- Kafka
- 클린 아키텍처
- fsync
- elasticsearch
- 기술사이트
- 에픽테토스
- completablefuture
- AWS
- Spring
- pecs
- meta character
- jhipster
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |