티스토리 뷰

반응형

※ 테스트환경 jdk1.7, tomcat7.0, maven, spring.3.2

처음 메서드단 캐시를 적용하시는 분들은 위해 최대한 빠르게 테스트 해보기 위한 목적으로 작성되었습니다.




※ 메서드단 캐시가 필요한 이유

간단하게 동접자가 만명인 환경에서 사이트의 메뉴정보를 DB에서 가져와야하는 경우에

캐싱을 하지않으면 1초동안 만명이 사이트를 방문시 DB에서 메뉴정보를 만번 쿼리해서 가져올 것이다. 그런데 메뉴정보를 가져오는 메서드를 3초동안만이라도 캐싱을 적용하게되면 1초동안 만명이 접속하더라도 1번만 DB쿼리를 하게된다. 엄청한 CPU소모를 절약할 수 있게되는 셈이다.



1. ehcache사용을 위한 디펜던시 추가


pom.xml 파일을 열어서 아래의 의존성라이브러리를 추가해준다.

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.1</version>
</dependency>



2. 스프링설정파일(xml) 캐시 설정 추가


스프링 설정파일에 아래의 캐시 설정을 추가한다.

<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

...

<!-- 캐시애노테이션 자동스캔설정 -->
<cache:annotation-driven />

<!-- 캐시매니저 선언 -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>


<!-- 캐시설정을위한별도설정파일 선언 -->

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
        p:config-location="/WEB-INF/config/cache/ehcache.xml"/>

...

</beans>



캐시설정을 위한 별도의 설정파일 경로에 /WEB-INF/config/cache/ehcache.xml 파일을 생성 후 아래와 같이 작성한다.

아래 파일에서 캐시되어야하는 메서드와 정책을 정한다.


<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../main/config/ehcache.xsd">


<diskStore path="java.io.tmpdir"/>


<!-- 캐시 정의 -->

<!--

name : 캐시의 이름이다. @Cacheable("캐시의 이름") 와 일치시켜줘야한다.

maxElementsInMemory : 메모리에 보유할 최대 데이터갯수

eternal : 한번 캐시하면 영원히 유지할 것인지의 여부

timeToIdleSeconds : 데이터가 지정된 시간(초단위)동안 재호출되지 않으면 휘발됨

timeToLiveSeconds : 한번 저장된 데이터의 최대 저장 유지 시간(초단위)

overflowToDisk : 메모리저장공간이 부족할때 Disk 사용여부

-->

<cache name="캐시이름"
        maxElementsInMemory="300"
        eternal="false"
        timeToIdleSeconds="500"
        timeToLiveSeconds="500"
        overflowToDisk="true"
        />


</ehcache>



3. 사용할 Dao또는 Service 메서드에 @Cacheable애노테이션 선언


@Cacheable : 캐시할 수 있는 메서드를 정의하는데 사용된다.

이 애노테이션을 사용한 메서드는 결과를 캐시에 저장하므로 재호출시에는 실제로 메서드를 실행시켜서 결과를 가져오지 않고 캐시에 저장된 결과를 바로 가져온다.


@Cacheable("캐시이름")
public List<ContentMenu> getContentMenuList(){
    logger.debug("메뉴목록쿼리");
    return getSqlSession().selectList("content.getContentMenuList");
}

이렇게 하면 getContentMenuList() 메서드는 캐시이름이라는 캐시와 연결된다.

이 기능은 기본적으로는 비활성화되어있지만 2번에서 <cache:annotation-driven/>을 선언해주었기 때문에 동작할 수 있다. 



이제 서버를 재 구동시켜서 테스를 해보면 처음에 가져올때만 메뉴목록쿼리라는 로그가 찍히고 두번째부터는 찍히지 않을 것이다.

이렇게 되면 캐시가 해당 메서드에 제대로 동작한다는 것이다.



캐싱이 정상적으로 되기 위한 메서드의 조건

1. 입력이 같으면 결과가 같다는 조건,

다시 말해서 해당 메서드 넘겨주는 매개변수의 값이 동일하면 리턴되는 결과값도 동일하다면 적용가능

ex)

public List<Map<String,Object>> getDbList() {

return getSqlSession().selectList("default.getDbList");

}

public List<Map<String,Object>> getDbList(int v){

return getSqlSession().selectList("default.getDbList2", v);

}

public List<Map<String,Object>> getDbList(int v, int v2){

Map<String,Object> p = new HashMap<String,Object>();

p.put("v", v);

p.put("v2", v2);

return getSqlSession().selectList("default.getDbList2", p);

}



2. 메서드의 리턴값이 커스텀 객체일경우 hashCode, equals 메소드를 오버라이드해서 재정의 해줘야 한다.

또한 직렬화도 되어야 한다.

ex)

public class CustomObj implements Serializable {

private static final long serialVersionUID = 1L;

private int no;

private String name;


@Override

public int hashCode(){

return new HashCodeBuilder().append(seq).toHashCode();

}

@Override

public boolean equals(Object o){

boolean b = false;

if(o instanceof CustomObj){

CustomObj c = (CustomObj) o;

b = c.getSeq() == this.seq;

}

return b;

}

public void setNo(int no){

this.no = no;

}

public int getNo(){

return this.no;

}

public void setName(String name){

this.name = name;

}

public String getName(){

return this.name;

}

}


반응형

'프로그래밍 > 스프링,자바' 카테고리의 다른 글

방문자수 측정하기  (0) 2018.06.15
이클립스(Eclips) Oxygen 설치하기  (0) 2017.10.05
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함