파란하늘의 지식창고
article thumbnail
반응형

Spring Data Redis의 문서를 보다 보면 아래와 같은 예제가 보인다.

  // inject the template as ListOperations
  @Resource(name="redisTemplate")
  private ListOperations<String, String> listOps;

Spring Boot의 RedisAutoConfiguration에서는 RedisTemplate과 StringRedisTemplate bean을 자동 설정해주고 있다.

@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<Object, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

그런데 처음 예제는 redisTemplate이란 이름의 ListOperations object를 inject 하고 있다.

언뜻 생각해보기엔 ListOperations가 RedisTemplate의 상위 interface인가 싶지만 살펴보면 RedisTemplate의 Hierarchy와 관련이 없다.

RedisTemplate hierarchy
ListOperations hierarchy

어떻게 ListOperations객체가 redisTemplate bean name으로 호출하여 inject 될 수 있는 것일까?

ConfigurationClassBeanDefinitionReader$ConfigurationClassBeanDefinition 에서 DefaultListableBeanFactory가 TypeConverter를 통해 조회 시 BeanUtils.findEditorByConvention method를 호출하게 된다.

해당 유틸에선 targetTypeName + "Editor" 규칙의 위치에 있는 PropertyEditor 상속 클래스를 찾아 해당 PropertyEditor를 통해 해당 객체를 convert 하게 된다.

Spring Data Redis는 PropertyEditor를 다음과 같이 구현해두었다.

각각은 binding된 타입의 + "Editor" 이름으로 설정되어 있다.

따라서 redisTemplate이란 이름의 ListOperations 가 선언되어 있으면 ListOperationsEditor가 수행되어 원래 redisTemplate에 해당하는 bean을 전달받아 ListOperations object로 convert 한다.
ListOperationsEditor의 내용은 다음과 같다.

class ListOperationsEditor extends PropertyEditorSupport {

	public void setValue(Object value) {
		if (value instanceof RedisOperations) {
			super.setValue(((RedisOperations) value).opsForList());
		} else {
			throw new IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class);
		}
	}
}

bean을 선언하지 않고 이렇게 사용하면 해당 autowired 객체의 generic type 매개 변수를 dynamic 하게 사용할 수 있고 또 autowired 처리되는 부분마다 재생성을 하여 간섭에서도 자유로울 수 있다.

반복적으로 사용하는 generic type 매개 변수의 data binding을 쓰는 경우 이 방법을 사용하는 것이 좋을 듯하다.

반응형
profile

파란하늘의 지식창고

@Bluesky_

내용이 유익했다면 광고 배너를 클릭 해주세요