最原始的进行缓存的方式:


最原始的使用缓存的方式是通过一个全局map保存获取过的数据,下次获取数据时先从map中提取,如果有就直接返回,如果没有就从数据库中去读取,然后放入map中,当然,在做更新操作时需要同步更新这个map中的数据。这种方式虽然原始,但是在一些简单的场景下已经够用了,比如Java的类加载器就是使用的这种方式缓存加载过的class。

 


 


通过ehcache以编程方式使用缓存:



跟上面的方式相同,但是缓存通过ehcache去管理,当然比使用map有N多种好处,比如缓存太大了快达到上限之后,将哪一部分缓存清除出去。这种方式完全是通过代码的方式使用ehcache缓存,虽然自由,却也很麻烦;有些比如单纯的场景下,不需要如此麻烦,直接通过注解就行了。



以前在Spring项目中要通过注解的方式使用缓存,比如借助一个jar包: ehcache-spring-annotations.jar,可以在googlecode上面下载,不过已经很久没有更新过了。



 



 



使用ehcache-spring-annotations.jar






Spring配置文件:



Spring与ehcache整合,通过Spring原生注解使用缓存_注解



    1. <?xml version= "1.0" encoding = "UTF-8"?>
    2. <beans xmlns= "http://www.springframework.org/schema/beans"
    3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:ehcache= "http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
    5. xsi:schemaLocation= "
    6. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    7. >
    8.
    9. <ehcache:annotation-driven cache-manager ="ehcacheManager" />
    10. <ehcache:config cache-manager = "ehcacheManager">
    11. <ehcache:evict-expired-elements
    12. interval= "60" />
    13. </ehcache:config >
    14. <bean id = "ehcacheManager"
    15. class= "org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
    16. <property name = "configLocation" value= "classpath:ehcache.xml" />
    17. </bean >
    18. </beans>



    共有两个注解:



    • @Cacheabele      :指定方法使用缓存
    • @TriggersRemove  :从缓存中移除对象



    在查询的方法上使用缓存 :



    Spring与ehcache整合,通过Spring原生注解使用缓存_注解



    1. @Cacheable(cacheName="platform.config")  


     



    在删除或更新的方法上清空缓存:



    Spring与ehcache整合,通过Spring原生注解使用缓存_注解



    1. @TriggersRemove(cacheName="platform.config", when=When.AFTER_METHOD_INVOCATION , removeAll=true)  
    2. public void
    3. this.configDao.update(config);
    4. }

     


    对于这种方式,这里不做详细探讨。



    在Spring 3.1以前,必须借助以上jar包才能支持以注解的方式使用缓存,但是从Spring 3.1开始,已经提供了原生的注解支持,当然也更加强大。



     



     



     



    Spring 3.1及以上版本的原生注解支持






    Spring配置文件:



    Spring与ehcache整合,通过Spring原生注解使用缓存_注解



    1. <?xml version= "1.0" encoding = "UTF-8"?>
    2. <beans xmlns= "http://www.springframework.org/schema/beans"
    3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:cache= "http://www.springframework.org/schema/cache"
    5. xsi:schemaLocation= "
    6. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    7. >
    8.
    9. <cache:annotation-driven cache-manager ="ehcacheCacheManager" />
    10. <bean id = "ehcacheCacheManager" class= "org.springframework.cache.ehcache.EhCacheCacheManager"
    11. p:cacheManager-ref= "ehcacheManager" />
    12. <bean id = "ehcacheManager"
    13. class= "org.springframework.cache.ehcache.EhCacheManagerFactoryBean" >
    14. <property name = "configLocation" value= "classpath:ehcache.xml" />
    15. </bean>
    16. </beans>



     



    Spring原生的缓存的注解共有四个:



    • @Cacheable  :应用到读取数据的方法上,即可缓存的方法,如查找方法:先从缓存中读取,如果没有再调用方法获取数据,然后把数据添加到缓存中
    • @CacheEvict :即应用到移除数据的方法上,如删除方法,调用方法时会从缓存中移除相应的数据
    • @CachePut   :应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存
    • @Caching    :上面三种注解配置方法时,一个方法只能使用三者之一。如果要使用多个,则需要使用@Caching

     



    在查询的方法上使用缓存:


    1. @Cacheable(value="platform.config"
    2. public



    指定key的生成规则:

    Spring与ehcache整合,通过Spring原生注解使用缓存_注解

    1. @Cacheable(value="platform.config", value="#configKey")  
    2. public

     


    缓存的key的生成:




    如果在Cache注解上没有指定key的话,会使用KeyGenerator生成一个key,默认提供了DefaultKeyGenerator生成器(Spring4之后使用SimpleKeyGenerator)。



    如果只有一个参数,就使用该参数作为key,否则使用SimpleKey作为key,比如有两个入参,那么key将是这样的形式: SimpleKey [DEVELOPER_NAME,chenfeng]。



    可以在Cache注解上指定key的生成规则,通过SpEL表达式指定规则。详细可以参考: ​​Spring Cache抽象详解​



    如果没有入参,又没有指定key,那么key将是“SimpleKey []”,这将很容易造成缓存的混乱,而且也不利于在更新的时候进行缓存的更新或移除。




    下面的代码入参是:SimpleKey []



    Spring与ehcache整合,通过Spring原生注解使用缓存_注解


    1. @Cacheable
    2. public


    下面的代码入参是:SimpleKey [DEVELOPER_NAME,chenfeng]



    Spring与ehcache整合,通过Spring原生注解使用缓存_注解


    1. @Cacheable
    2. public



     



    在更新的方法上更新缓存:




    Spring与ehcache整合,通过Spring原生注解使用缓存_注解



      1. @CachePut(value=PlatformPrivateConstants.CACHE_NAME_CONFIG, key="#config.configKey")  
      2. public



      通过"#config.configKey"指定以入参config对象的configKey属性值作为缓存的key。



      更新的方法必须将要缓存的对象作为返回值,只有这个返回的对象才会放入缓存中,如果在返回值被返回之前篡改了其内部数据,也会被反映到缓存中。



       



       



      指定正确的key以防止缓存混乱:




      下面两个方法,前者通过configKey查询对象,后者通过configKey查询对象中的configValue属性值:



      Spring与ehcache整合,通过Spring原生注解使用缓存_注解



        1. public
        2. public



        Spring与ehcache整合,通过Spring原生注解使用缓存_注解



        1. @Cacheable(value="platform.config")  
        2. public
        3. @Cacheable(value="platform.config")
        4. public



        比如先调用了querySingleConfig方法,那么查询到的SystemConfig对象就会以"DEVELOPER_NAME"为key存入缓存中,然后调用querySingleConfigValue方法,因为仍会以"DEVELOPER_NAME"作为key从缓存中提取数据,这时就会从缓存中取得了刚才那个SystemConfig对象,却当作是字符串型的configValue属性值返回了。

         



        所以必须为这两个方法指定不同的缓存key:



        Spring与ehcache整合,通过Spring原生注解使用缓存_注解



        1. @Cacheable(value="platform.config", key = "#configKey.concat('_object'))  
        2. public
        3. @Cacheable(value="platform.config")
        4. public



        configKey值后接" _object"作为key,而后者使用入参 configKey值为key,就不会相互覆盖了。



         



         



        在更新的方法上同时更新多个缓存:




        在查询时,可能通过id查询也可能通过name查询,这样在缓存中就存有两份数据,在更新的时候就必须同时更新这两份缓存。


          1. @Cacheable(value="platform.config", key = "#configId)  
          2. public SystemConfig querySingleConfig(long
          3. @Cacheable(value="platform.config", key = "#configKey)
          4. public



          通过@Caching注解组合多个@CachePut注解,从而在调用更新方法时同时更新多份缓存(以不同的key存在于缓存中)



          Spring与ehcache整合,通过Spring原生注解使用缓存_注解



          1. @Caching(put={@CachePut(value="platform.config" , key="#config.configId"),  
          2. @CachePut(value="platform.config" , key="#config.configKey"
          3. public



           



           



          在更新方法上同时更新和清除缓存:






          上面的方法虽然可以同时更新多个缓存,但是必须保证这些缓存的值是完全一样的,比如上面两个方法缓存的都是SystemConfig对象,而对于下面的方法就无能为力了,因为下面的方法缓存的是SystemConfig对象的configValue属性值,而上面的方式只能把作为返回值的SystemConfig对象更新到缓存中。



          Spring与ehcache整合,通过Spring原生注解使用缓存_注解



          1. @Cacheable(value="platform.config")  
          2. public



          对于这种情况,通过@CacheEvict清除那些无法更新的缓存,这样下次获取不到这些缓存就会越过缓存从数据库查询最新的数据。



          Spring与ehcache整合,通过Spring原生注解使用缓存_注解


          1. @Caching(evict={@CacheEvict(value="platform.config", key="#config.configKey"
          2. @CachePut(value="platform.config", key="#config.configId.concat('_object')"),
          3. @CachePut(value="platform.config", key="#config.configKey.concat('_object')"
          4. public


           



           



          使用缓存的业务层的设计宗旨:




          使用缓存的业务类应尽量精简、方法应尽可能少,只保留最紧要的方法。



          因为进行更新操作时需要考虑每一个的获取数据的方法,必须将可能被更新操作波及的所有缓存进行更新或清除,如果获取数据的方法过多,这个工作量将变得很大,并且很容易出错,比如忘记了更新或清除某一份缓存,而大型项目中这种错误可能难以被发 现。 另外,保存多份缓存,也增加了ehcache的负担,因为它需要维护这些缓存数据,比如需要判断哪些缓存最久未使用而从缓存中移除等。



          所以应该在处于低层的业务类上使用缓存,而在高层的业务类上提供丰富的获取数据的方法,高层业务类所有操作均调用底层的业务类实现。



          对于不会被频繁调用的方法,不要进行缓存,没有实际意义,还无谓增大ehcache的负担,并且浪费宝贵的内存。