1. 程式人生 > >在web應用中使用快取技術

在web應用中使用快取技術

快取是網站架構中必不可少的關鍵點之一,特別是對於構建高效能高響應的網站來說更是不可或缺的技術。

在這裡記錄一下 我是如何在我的web應用中使用快取的。

首先專案環境使用spring,framework版本4.x,快取管理器選用ehcache+redis。

這裡只講解一下快取在專案中的用法,不涉及快取叢集的搭建。不管快取管理器是否是叢集狀態,這裡都不會影響框架內的使用。

首先,配置ehcache快取管理器,

新建一個CacheConfig.java做為spring的快取容器配置類,配置net.sf.ehcache包內的CacheManager,這裡使用spring內自帶的EhCacheManagerFactoryBean來生成ehcache的CacheManager,

    @Bean
    public EhCacheManagerFactoryBean ehcache() {
        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
        ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("org/fast/web/sys/cache/ehcache.xml"));
        return ehCacheManagerFactoryBean;
    }

這裡需要注意一下,在org.springframework.cache包內,也有一個名為CacheManager的介面類,這個介面是做為spring內的唯一的快取容器而存在的,我們需要為它注入一個實現,這個實現可以是net.sf.ehcache包內的CacheManager,這樣做就表明我們的web應用程式只使用ehcache做為我們的快取容器。例如如下程式碼:
    @Bean
    public EhCacheManagerFactoryBean ehcache() {
        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
        ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("org/fast/web/sys/cache/ehcache.xml"));
        return ehCacheManagerFactoryBean;
    }

    @Bean
    public EhCacheCacheManager ehcacheManager(CacheManager cm) {
        return new EhCacheCacheManager(cm);
    }

這裡使用了spring包內的EhCacheCacheManager類,這個類其實也是CacheManager介面的實現,只不過spring專門為ehcache做了一些優化,使用這個類需要構造器注入ehcache包內的cachemanager。

關於ehcache的配置檔案ehcache.xml的配置方式,我會在另一篇文章內說明。

在這裡我們不使用EhCacheCacheManager類作為spring的CacheManager介面的實現注入。我們先配置另一個快取管理器---redis

這裡我們使用spring內的redis連線工廠類JedisConnectionFactory來配置redis的連線資訊,

@Bean
    public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig config) {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setPoolConfig(config);
        jedisConnectionFactory.afterPropertiesSet();
        return jedisConnectionFactory;
    }

這裡,我沒有配置連線資訊,使用連線工廠預設的引數。其中hostName,port,password等資訊作為JedisConnectionFactory的成員屬性,可以直接使用set方法自定義,這裡不在贅述。

其中JedisPoolConfig是我注入的jedis連線池資訊,用來細粒化redis連線配置資訊,更多內容可以參考spring-data-redis的官方api文件

    @Bean
    public JedisPoolConfig config() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMinEvictableIdleTimeMillis(1200000);//20分鐘空閒超時斷開連線
        config.setMinIdle(1);//保留一個空閒連線
        config.setTestOnBorrow(true);//檢查連線有效性
        return config;
    }

Jedis連線工廠可以用來獲取jedis物件,jedis物件是用來操作redis客戶端的java api,這裡有一篇詳細的介紹可以參考:Redis客戶端:Jedis

當然,我們不會使用這種方式來應用redis,因為你必須手動維護redis連線資源的開啟和關閉以及執行緒安全等問題,如果空閒的redis連線不及時關閉,很快大量的快取操作會將redis連線數佔滿,以至於報錯。

因此,這裡我使用spring提供的RedisTemplate類來操作redis,這與jdbcTemplate和jpaTemplate如出一轍,都是為了簡化crud操作而生,redisTemplate內建的成員變數都是執行緒安全的,可以放心的將其注入為單例模式來使用。

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

有了redisTemplate之後,我們就可以注入一個RedisCacheManager(也實現了spring的CacheManager介面),將redis用作為我的web應用的快取管理器。

不過這裡我也不會這麼做,接下來我會配置CompositeCacheManager類,將其作為spring的CacheManager的實現,注入到ioc容器中。

@Bean
    public CacheManager cacheManager(net.sf.ehcache.CacheManager cm, RedisTemplate redisTemplate) {
        CompositeCacheManager cacheManager = new CompositeCacheManager();

        List caches = new ArrayList<Object>() {
            {
                add(new EhCacheCacheManager(cm));
                add(new RedisCacheManager(redisTemplate));
            }
        };
        cacheManager.setCacheManagers(caches);
        return cacheManager;
    }
可以很輕鬆的看出,這個bean集成了ehcache和redis,相當於聯合使用兩種快取管理器(當然也可以是N種)。需要注意的是,應用存取快取的順序是按照這裡的list內的順序來決定的。

解決了快取的配置之後,接下來就是在我的web應用中使用快取了,我會使用最為便捷的spring快取註解來構建最為便捷的快取存取模式,當然也可以在適當的地方自定義快取存取。

spring的快取註解大部分都是圍繞切面來展開使用的,例如 利用註解來建立切面,來攔截方法的呼叫,在方法呼叫之前返回快取中的資料,因此使用註解快取需要我們保證相同方法相同引數的每次返回值必須是相同的

主要是使用下面4種快取註解:

asd

@Cacheable  -> 表明spring在呼叫方法之前,首先應該在快取中查詢方法的返回值,如果這個值能夠找到,就會返回快取的值。否則,這個方法就會被呼叫,返回值會放入快取中。

@CachePut  ->表明spring應該將方法的返回值放入快取中。在方法的呼叫前並不會檢查快取,方法始終都會被呼叫。

@CacheEvict ->表明spring應該在快取中清除一個或多個條目

@Caching -> 這是一個分組的註解,能夠同時應用多個其他的快取註解