[스프링 3.1] cache:annotation-driven을 확장하고파…

스프링은 빈 설정을 간편히 하라고 네임스페이스를 많이 제공해주는데, 실제로 개발할 때 매우 편합니다. 그냥 스프링이 제공해주는 그.대.로. 사용할 때에만요. 스프링 캐시의 핵심 API는 다음과 같습니다.

CacheManager: EhCache의 CacheManager와 이름이 같지만, 이건 패키지가 다르고 스프링이 제공하는 캐시 추상화의 핵심 인터페이습니다.

Cacahe: 이건 CacheManager에서 get(“캐시 이름”)을 사용해서 가져올 수 있는 클래스고요.

KeyGenerator: 캐시 키값을 생성하는 방식을 Strategy Pattern화 시켜둔걸로 보시면 됩니다. 기본 구현체로는 해당 객체의 hashCode()를 사용하는 DefaultKeyGenerator를 사용하는데, 분산 환경에는 적절치 못할 겁니다.

사실 얘네들 정도를 확장하려면, 더 깊게 들어가지 않아도 됩니다. 그런데 저는 좀 더 필요한 경우를 보게 됐습니다; 보게 됐다? 요구 사항이 있었습니다;

아무튼 이런 것들을 이용해서 Cache AOP를 제공할 때의 주요 API는 다음과 같습니다.

CacheInterceptor: MethodInterceptor의 구현체로, 스프링 AOP에서 캐시 기능을 Advice를 구현하나 핵신 구현체입니다.

CacheOperationSource: 이건 CacheInterceptor에서 사용하는 인터페이스로, 특정 메서드에서 수행할 캐시 오퍼레이션이 무엇인지 알려주는 역할을 합니다. 기본 구현체로는 AnnotationCacheOperationSource를 사용합니다.

BeanFactoryCacheOperationSourceAdvisor: 스프링 AOP를 아시는 분들은 뭔지 잘 아시겠죠. Advisor니까 Advice와 Pointcut의 조합이구요. 이 안에 기본으로 CacheOperationSourcePoincut이 Pointcut으로 들어있습니다. 따라서 캐시 적용 가능한 메서드에만 포인트컷이 걸립니다.

이것들을 모두 이용하는게…

[xml]
<cache:annotation-driven/>
[/xml]

이 한줄입니다. 이걸 풀어서 적으면 이렇게 됩니다.

[xml]
<!– cache setup –>
<bean id="annotationCacheOperationSource" class="org.springframework.cache.annotation.AnnotationCacheOperationSource" />
<bean id="cacheInterceptor" class="org.springframework.cache.interceptor.CacheInterceptor">
<property name="cacheDefinitionSources" ref="annotationCacheOperationSource" />
<property name="cacheManager" ref="cacheManager"/>
</bean>
<bean id="cacheAdvisor" class="org.springframework.cache.interceptor.BeanFactoryCacheOperationSourceAdvisor">
<property name="cacheDefinitionSource" ref="annotationCacheOperationSource" />
<property name="advice" ref="cacheInterceptor" />
</bean>

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache" />
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="ehcache.xml"/>
[/xml]

이 중에서 원하는 객체를 확장해서 교체하면 되겠죠. 끝~

STS 스프링 3.1 지원

Spring Tool Suite 2.8 버전 M2가 나왔습니다.

http://www.springsource.org/node/3268

주요 기능은 다음과 같습니다.

  • Spring 3.1 support
  • c-Namespace content-assist, quick-fix and validation
  • update to m2e 1.0
  • support for Groovy 1.8.2
  • enhanced type inferencing for Groovy
  • support for Grails 2.0.0.M2
  • improved Grails-aware rename refactorings
  • enhancements to the Gradle support

빌드 툴로 Gradle이 뜨는 추세인가 보네요. Spring-Social 프로젝트를 빌드 할 때 한번 써봤지만, 느낌은 Ant와 Maven을 교묘하게 합쳐놓은 것 같은 느낌이랄까요.. 흠..

image

EGit와 Atlassian connector도 기본 설치군요;;

JCO 운영진에서 사퇴합니다.

뜻이 맞지 않는 곳에 제 에너지를 낭비할 수는 없었습니다. 지난 JCO(http://jco.or.kr)에서 발표자 공개 모집을 통해서 JCO 발표자를 커뮤니티 장들이 알아서 뽑는 형태가 아닌 열린 형태로 바꾸는 것만 해도 굉장히 피곤하고 힘들었습니다. 그에대한 보답은? 없습니다. 아무런 보람이 느껴지지 않았습니다.

이번에는 스터디 비용 지원과 JCO 홈페이지 개선안을 냈지만, 발표자 공개 모집때와 똑같은 수순을 밟게 할 뿐이더군요. 정작 중요한 것은 JCO 법인화 뿐이랍니다. 이쯤 되면 이제는 내가 왜 이런 모임에 내 에너지를 쏟아야 하는가 고민이 되죠.

그래서 그만 둡니다. 열심히 해도 보람이 느껴지지 않는 곳에 오래 몸을 담을 수는 없습니다. 남아 계신 분들은 아무쪼록 법인화 잘 하시고, 돈 잘 버는 JCO 만드시기 바랍니다.

장모님 멋지다!!!

오늘 진짜 멋진 모습을 보았습니다.

회사에서 개발자 밤샘 코딩 행사를 하는데 자원봉사를 했습니다. 딱히 그 행사에 애착이 있다거나 그런 것은 아니고, 다만 도와주고 싶은 분이 운영을 하신다기에, 그 분이 자원봉사를 필요로 하신다기에 도와드렸지요.

그런데 그만 심하게 몸살이 나고 말았습니다. 마침 아내도 감기로 고생하고 있는데 저까지 완전 쓰려져서 잠만자다가 간신히 일어나서 돌아다니는 정도였죠. 어제 집에 있던 캠코더로 집안 풍경을 찍었으면 정말 왠만한 좀비영화보다 더 재밌는 장면이 많았을 것 같은데, 그걸 놓친게 정말 후회됩니다.

아무튼, 어제 너무 아픈데 배는 고프고, 이럴때 보양식이라도 먹고 빨리 나아야 내일(즉 오늘) 회사에서 강의를 제대로 할텐데.. 라는 생각밖에는 머리에 없었습니다. 그때마침 예전에 장모님 댁에서 먹었던 추어탕이 생각나더군요.

아내에게 장모님께 추어탕 좀 부탁드리면 안될까..라고 했는데 아내가 잘 전화를 해줘서 어제 점심 저녁때 정말 맛있는 추어탕을 먹을 수 있었습니다. 오늘 이렇게 다시 기운차리고 무사히 강의도 끝낼 수 있었던 건 다 장모님 덕분이지요. 정말 어제 그 추어탕은 다신 잊지 못할 것 같습니다.

우리 부부는 결혼할 때 최대한 부모님께 손을 벌리지 말고 독립적으로 살자고 했고 실제로 결혼에 필요한 거의 모든 것을 우리 부부 자력으로 해결했습니다. 하지만 서연이가 생긴 이후로는 정말 많이 힘들더군요. 아내가 다니던 직장도 그만두고, 종일 서연이만 돌보는 것도 힘들고, 나도 집에서 제대로 쉬지 못하고 공부를 못하니까 나름대로 답답하고 힘들고 그렀쵸.. 그런 중간 중간 계속해서 우리 부부를 다독여 주고 힘들때마다 도움주시는 장모님이 정말 감사하고 고맙습니다.

그리고.. 오늘 퇴근했더니, 이게 왠걸… 주차장에 자동차가 선물로 세워져 있군요. 운전도 잘 못하는 사위와 서연이 데리고 바깥에 다니기 힘든 아내를 위해서 차까지 사주시다니… 정말 감사합니다. 제가 꼭 운전연습 많이 해서 다음부턴 제가 아내랑 서연이 태우고 다니겠습니다. 안그래도 차는 사야지 사야지 했는데, 도무지 요즘 가계 상황에서는 썩 여의치 않은 시기였거든요.

그걸 또 잘 아시고 이렇게 도와주시니 정말 정말 감사합니다.

앞으로도 열심히 잘 살겠습니다.

ps: 제가 말주변이 별로 없어서 글로 남기옵니다.

 

[스프링 3.1 Cache] 테스트하기

캐시 기능을 테스트 하는 방법을 간단하게 소개합니다.

캐시에 들어있는지 없는지 확인하면 되겠죠. 쉽게, CacheManager라는 것을 사용하면 됩니다. 어차피 스프링 캐시를 사용하려면 등록해야 하는 빈입니다. CacheManager는 인터페이스이고, 사용하려는 캐시에 따라 다른 CacheManager 빈을 등록해야 하죠. EhCache를 사용한다면, EhCacheCacheManager를 등록해야 합니다.

스프링 레퍼런스에도 EhCache를 사용하는 경우의 예제 코드를 제공하고 있는데요. 지금 스프링 레퍼런스 문서에 있는 코드는 소소한 문제가 있습니다. 버그 리포팅을 했으니 조만간 고쳐질 겁니다.

[xml]
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:/ehcache.xml"/>
[/xml]

이런식으로 빈을 등록하게 되지요. 여기서 cachaManager라는 빈 id는 cache:annotation-driven에서 사용하는 기본값이기 때문에 되도록이면 cacheManager라고 id를 적어주는게 좋겠습니다. 물론 원하는 이름을 적은 뒤에 cache:annotation-driven에 cache-manager라는 속성에 명시해주어도 됩니다.

그리고 테스트는 이렇게 할 수 있습니다.

[java]
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/applicationContext.xml")
public class MemberServiceImplTest {

@Autowired MemberService service;
@Autowired CacheManager cacheManager;

@Test
public void getMemberCache(){
//GIVEN
Cache memberCache = cacheManager.getCache("member");

//WHEN
service.getAMember(1);
//THEN
assertThat(memberCache.get(1), is(notNullValue()));

//WHEN
service.getAMember(2);
//THEN
assertThat(memberCache.get(2), is(notNullValue()));

//WHEN
service.getAMember(3);
//THEN
assertThat(memberCache.get(3), is(notNullValue()));
}
[/java]

참 쉽죠?