五隘道、Spring 3.1新增的緩存機制

啟用Spring緩存:

Spring配置文件專門為緩存提供了一個cache:命名空間赌渣,為了啟用Spring緩存世落,需要在配置文件中導入cache:命名空間淮腾。導入context:命名空間后,啟用Spring緩存還要兩步屉佳。

  • 在Spring配置文件中添加<cache:annotation-driven cache-manager="緩存管理器ID"/>谷朝,該元素指定Spring根據(jù)注解來啟用Bean級別或方法級別的緩存。
  • 針對不同的緩存實現(xiàn)配置對應的緩存管理器忘古。

1、Spring內(nèi)置緩存實現(xiàn)的配置:

Spring內(nèi)置的緩存實現(xiàn)只是一種內(nèi)存中的緩存诅诱,并非真正的緩存實現(xiàn)髓堪,因此通常只能用于簡單的測試環(huán)境,不建議在實際項目中使用Spring內(nèi)置緩存的實現(xiàn)娘荡。Spring內(nèi)置的緩存實現(xiàn)使用SimpleCacheManager作為緩存管理器干旁,使用SimpleCacheManager配置緩存非常簡單,直接在Spring容器中配置該Bean炮沐,然后通過<property.../>驅(qū)動該緩存管理器執(zhí)行setCaches()方法來設置緩存區(qū)即可争群。
SimpleCacheManager是一種內(nèi)存中的緩存區(qū),底層直接使用了JDK的ConcurrentMap來實現(xiàn)緩存大年,SimpleCacheManager使用了ConcurrentMapCacheFactoryBean作為緩存區(qū)换薄,每個ConcurrentMapCacheFactoryBean配置一個緩存區(qū)。

<!--使用SimpleCacheManager配置Spring內(nèi)置的緩存管理器-->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
    <!--配置緩存區(qū)-->
     <property name="caches">
         <set>
             <!--使用ConcurrentMapCacheFactoryBean配置緩存區(qū)翔试,下面列出多個緩存區(qū)轻要,p:name用于緩存區(qū)指定名字-->
             <bean class="org.springframework.cache.ConcurrentMapCacheFactoryBean" p:name="defaule"/>
              <bean class="org.springframework.cache.ConcurrentMapCacheFactoryBean" p:name="users"/>
        </set>
     </property>
</bean>

2、EhCache緩存實現(xiàn)的配置:

在配置EhCache緩存實現(xiàn)之前垦缅,首先需要將EhCache緩存的JAR包添加到類加載路徑中冲泥。只要將Hibernate解壓路徑下 lib\optional\ehcache\路徑下的ehcache-core-2.4.3.jar和slf4j-api-1.6.1.jar復制到項目類加載路徑下即可。

為了使用EhCache壁涎,同樣需要在應用的類加載路徑下添加一個ehcache.xml配置文件凡恍。如下配置兩個緩存區(qū):
ehcache.xml

<?xml version="1.0" encoding="gbk"?>
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
          maxElementsInMemory="10000"
          eternal="false"
          timeToIdleSeconds="120"
          timeToLiveSeconds="120"
          maxElementsOnDisk="10000000"
          diskExpiryThreadIntervalSeconds="120"
          memoryStoreEvictionPolicy="LRU"/>
<cache name="users"
          maxElementsInMemory="10000"
          eternal="false"
          timeToIdleSeconds="120"
          timeToLiveSeconds="120"
          maxElementsOnDisk="10000000"
          diskExpiryThreadIntervalSeconds="120"
          memoryStoreEvictionPolicy="LRU"/>
</ehcache>

使用@Cacheable執(zhí)行緩存:

@cacheable可用于修飾類或修飾方法,當使用@Cacheable修飾類時怔球,用于高數(shù)Spring在類級別上進行緩存---程序調(diào)用該類的實例的任何方法時都需要緩存嚼酝,而且共享同一個緩存區(qū);當使用@Cacheable修飾方法時竟坛,用于告訴Spring在方法級別上進行緩存---只有當程序調(diào)用該方法時才需要緩存革半。

1碑定、類級別的緩存:

@service("userService")
@Cacheable(value="users")
public class UserServiceImpl implements UserService{
    public User getUsersByNameAndAge(String name,int age){
        System.out.println("--正在執(zhí)行findUsersByNameAndAge()查詢方法--");
        return new User(name,age);
    }
    public User getAnotherUser(String name,int age){
        System.out.println("--正在執(zhí)行findAnotherUser()查詢方法--");
        return new User(name,age);
    }
}

此處所指的緩存的意義是:當程序第一次調(diào)用該類的實例的某個方法時,Spring緩存機制會將該方法返回的數(shù)據(jù)放入指定的緩存區(qū)---就是@Cacheable注解的value屬性值所指定的緩存區(qū)(注意此處指定的數(shù)據(jù)放入users緩存區(qū)又官,這就要求前面為緩存管理器配置過users的緩存區(qū))延刘。以后程序調(diào)用該類的實例的任何方法時,只要傳入的參數(shù)相同六敬,Spring將不會真正指定該方法碘赖,而是直接利用緩存區(qū)中的數(shù)據(jù)。

public class SpringTest{
    public static void main(String[] args){
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
        UserService us=ctx.getBean("userService",UserService.class);
        //第一次調(diào)用us對象的方法時會執(zhí)行該方法外构,并緩存該方法的結(jié)果
        User u1=us.getUserNynameAndAge("張三",500);
        //第二次調(diào)用us對象的方法時直接利用緩存的數(shù)據(jù)普泡,并不真正執(zhí)行該方法
        User u2=us.getAnotherUser("張三","500");
        System.out.println(u1==u2);
    }
}

輸出:

--正在執(zhí)行findUsersByNameAndAge()查詢方法--
true

類級別的緩存默認以所有方法的參數(shù)作為key來緩存方法返回的數(shù)據(jù)---同一個類不管調(diào)用哪個方法,只要調(diào)用方法時傳入的參數(shù)相同审编,Spring都會直接利用緩存區(qū)中的數(shù)據(jù)撼班。使用@Cacheable時可指定如下屬性:

  • value:必須屬性。該屬性可指定多緩沖區(qū)的名字垒酬,用于指定將方法返回值放入指定的緩存區(qū)內(nèi)砰嘁。
  • key:通過SpEL表達式顯示指定緩存的key.
  • condition:該屬性指定一個返回boolean值得SpEL表達式,只有當該表達式返回true是勘究,Spring才會緩存方法的返回值矮湘。
  • unless:該屬性指定一個返回boolean值得SpEL表達式,當表達式返回true時口糕,Spring就不緩存返回值缅阳。

與@Cacheable注解功能類似的還有一個@CachePut注解,@CachePut注解同樣會讓Spring將方法返回值放入緩沖區(qū)景描。與@Cacheable不同的是十办,@CachePut修飾的方法不會讀取緩存區(qū)中的數(shù)據(jù)---這意味著不管緩存區(qū)是否有數(shù)據(jù),@CachePut總會告訴Spring要重新執(zhí)行這些方法超棺,并再次將方法返回值放入緩沖區(qū)橘洞。

condition屬性與unless屬性的功能基本相似,但規(guī)則恰好相反:當condtion指定的條件為true時说搅,Spring緩存機制才會執(zhí)行緩存炸枣;當unless指定的條件為true時,Spring緩存機制就不執(zhí)行緩存弄唧。

@service("userService")
@Cacheable(value="users" condition="#age<100")
public class UserServiceImpl implements UserService{...}
public class SpringTest{
    public static void main(String[] args){
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
        UserService us=ctx.getBean("userService",UserService.class);
        //調(diào)用方法時age參數(shù)不小于100适肠,因此不會緩存
        User u1=us.getUsersByNameAndAge("張三",500);
        User u2=us.getAnotherUser("張三",500);
        System.out.println(u1==u2);//輸出false
        //調(diào)用方法時age參數(shù)小于100,因此會緩存
        User u3=us.getUsersByNameAndAge("張三",50);
        User u4=us.getAnotherUser("張三",50);
        System.out.println(u3==u4);//輸出true
    }
}

2候引、方法級別的緩存:

使用@Caheable修飾方法時侯养,就可以控制Spring在方法級別進行緩存,這樣當程序調(diào)用該方法時澄干,只要傳入的參數(shù)相同逛揩,Spring就會使用緩存柠傍。

@service("userService")
public class UserServiceImpl implements UserService{
   @Cacheable(value="user1")
   public User getUsersByNameAndAge(String name,int age){
        System.out.println("--正在執(zhí)行findUsersByNameAndAge()查詢方法--");
        return new User(name,age);
    }
    @Cacheable(value="user2")
    public User getAnotherUser(String name,int age){
        System.out.println("--正在執(zhí)行findAnotherUser()查詢方法--");
        return new User(name,age);
    }
}

上面兩個程序分別使用了users1、users2兩個緩存區(qū)辩稽,因此還需要在ehcache.xml文件中配置這兩個緩存區(qū)惧笛。

public class SpringTest{
    public static void main(String[] args){
        ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
        UserService us=ctx.getBean("userService",UserService.class);
        //第一次調(diào)用us對象的方法時會執(zhí)行該方法,并緩存該方法的結(jié)果
        User u1=us.getUserNynameAndAge("張三",500);
        //由于getAnotherUser()方法使用另一個緩存區(qū),因此無法使用getUserNynameAndAge()方法緩存的數(shù)據(jù)
        User u2=us.getAnotherUser("張三","500");
        System.out.println(u1==u2);//返回false
        //getAnotherUser()方法已經(jīng)執(zhí)行過一次了,故下面代碼使用緩存
        User u3=us.getAnotherUser("張三","500");
        System.out.println(u2==u3);//返回true
    }
}

使用@CacheEvict清除緩存:

被@CacheEvict注解修飾的方法可用于清除緩存砸民,使用@CacheEvict注解時可指定如下屬性:

  • value:必需屬性。用于指定方法用于清除哪個緩存區(qū)的數(shù)據(jù)各谚。
  • allEntries:該屬性指定是否清除整個緩存區(qū)的內(nèi)容。
  • beforeInvocation:該屬性指定是否在執(zhí)行方法之前清除緩存到千。默認是在方法執(zhí)行成功之后清除緩存昌渤。
  • condition:該屬性指定一個SpEL表達式,只有當該表達式為true時才清除緩存憔四。
  • key:通過SpEL表達式顯示指定緩存的key膀息。
@service("userService")
    @Cacheable(value="users")
public class UserServiceImpl implements UserService{
   
   public User getUsersByNameAndAge(String name,int age){
        System.out.println("--正在執(zhí)行findUsersByNameAndAge()查詢方法--");
        return new User(name,age);
    }
    
    public User getAnotherUser(String name,int age){
        System.out.println("--正在執(zhí)行findAnotherUser()查詢方法--");
        return new User(name,age);
    }
    //根據(jù)name、age參數(shù)清除緩存
    @CacheEvict(value="users")
    public void evictUser(String name,int age){
        System.out.println("--正在清空"+name+"加矛,"+age+"對應的緩存--")
    }
    
    //指定清除user緩存區(qū)所有的緩存數(shù)據(jù)
    @CacheEvict(value="users",allEntries=true)
    public void evictALL(){
        System.out.println("--正在清除整個緩存--")
    }
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末履婉,一起剝皮案震驚了整個濱河市煤篙,隨后出現(xiàn)的幾起案子斟览,更是在濱河造成了極大的恐慌,老刑警劉巖辑奈,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苛茂,死亡現(xiàn)場離奇詭異,居然都是意外死亡鸠窗,警方通過查閱死者的電腦和手機妓羊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稍计,“玉大人躁绸,你說我怎么就攤上這事〕枷” “怎么了净刮?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長硅则。 經(jīng)常有香客問我淹父,道長,這世上最難降的妖魔是什么怎虫? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任暑认,我火速辦了婚禮困介,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蘸际。我一直安慰自己座哩,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布捡鱼。 她就那樣靜靜地躺著八回,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驾诈。 梳的紋絲不亂的頭發(fā)上缠诅,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音乍迄,去河邊找鬼管引。 笑死,一個胖子當著我的面吹牛闯两,可吹牛的內(nèi)容都是我干的褥伴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼漾狼,長吁一口氣:“原來是場噩夢啊……” “哼重慢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起逊躁,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤似踱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后稽煤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體核芽,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年酵熙,在試婚紗的時候發(fā)現(xiàn)自己被綠了轧简。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡匾二,死狀恐怖哮独,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情察藐,我是刑警寧澤皮璧,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站转培,受9級特大地震影響恶导,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浸须,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一惨寿、第九天 我趴在偏房一處隱蔽的房頂上張望邦泄。 院中可真熱鬧,春花似錦裂垦、人聲如沸顺囊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽特碳。三九已至,卻和暖如春晕换,著一層夾襖步出監(jiān)牢的瞬間午乓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工闸准, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留益愈,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓夷家,卻偏偏與公主長得像蒸其,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子库快,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容