qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請?jiān)L問 http://qaseven.github.io/

          使用Memcached、Spring AOP構(gòu)建數(shù)據(jù)庫前端緩存框架

           上回說到Memcahed的安裝及java客戶端的使用,現(xiàn)在我們使用memcached、Spring AOP技術(shù)來構(gòu)建一個(gè)數(shù)據(jù)庫的緩存框架。

            數(shù)據(jù)庫訪問可能是很多網(wǎng)站的瓶頸。動不動就連接池耗盡、內(nèi)存溢出等。前面已經(jīng)講到如果我們的網(wǎng)站是一個(gè)分布式的大型站點(diǎn),那么使用memcached實(shí)現(xiàn)數(shù)據(jù)庫的前端緩存是個(gè)很不錯(cuò)的選擇;但如果網(wǎng)站本身足夠小只有一個(gè)服務(wù)器,甚至是vps的那種,不推薦使用memcached,使用Hibernate或者M(jìn)ybatis框架自帶的緩存系統(tǒng)就行了。

            一、開啟memcached服務(wù)器端服務(wù)

            如果已經(jīng)安裝了memcached服務(wù)器端程序,請確認(rèn)服務(wù)器端服務(wù)已開啟。

            二、引入jar

            1.  alisoft-xplatform-asf-cache-2.5.1.jar

            2.  commons-logging-1.0.4.jar

            3.  hessian-3.0.1.jar

            4.  log4j-1.2.9.jar

            5.  stax-api-1.0.1.jar

            6.  wstx-asl-2.0.2.jar

            三、創(chuàng)建memcached客戶端配置文件

          <memcached>
           <!-- name 屬性是程序中使用Cache的唯一標(biāo)識;socketpool 屬性將會關(guān)聯(lián)到后面的socketpool配置; -->
           <client name="mclient_0" compressEnable="true" defaultEncoding="UTF-8"
            socketpool="pool_0">
            <!-- 可選,用來處理出錯(cuò)情況 -->
            <errorHandler>com.alisoft.xplatform.asf.cache.memcached.MemcachedErrorHandler
            </errorHandler>
           </client>

           <!--
            name 屬性和client 配置中的socketpool 屬性相關(guān)聯(lián)。
            maintSleep屬性是后臺線程管理SocketIO池的檢查間隔時(shí)間,如果設(shè)置為0,則表明不需要后臺線程維護(hù)SocketIO線程池,默認(rèn)需要管理。
            socketTO 屬性是Socket操作超時(shí)配置,單位ms。 aliveCheck
            屬性表示在使用Socket以前是否先檢查Socket狀態(tài)。
           -->
           <socketpool name="pool_0" maintSleep="5000" socketTO="3000"
            failover="true" aliveCheck="true" initConn="5" minConn="5" maxConn="250"
            nagle="false">
            <!-- 設(shè)置memcache服務(wù)端實(shí)例地址.多個(gè)地址用","隔開 -->
            <servers>127.0.0.1:11211</servers>
            <!--
             可選配置。表明了上面設(shè)置的服務(wù)器實(shí)例的Load權(quán)重. 例如 <weights>3,7</weights> 表示30% load 在
             10.2.224.36:33001, 70% load 在 10.2.224.46:33001
            
            <weights>3,7</weights>
            -->
           </socketpool>
          </memcached>


            四、創(chuàng)建memcached客戶端程序

            客戶端工具類:

          package com.hl.usersmanager.memcached.client;

          import com.alisoft.xplatform.asf.cache.ICacheManager;
          import com.alisoft.xplatform.asf.cache.IMemcachedCache;
          import com.alisoft.xplatform.asf.cache.memcached.CacheUtil;
          import com.alisoft.xplatform.asf.cache.memcached.MemcachedCacheManager;

          public class MemcachedCache {
           private ICacheManager<IMemcachedCache> manager;
           private IMemcachedCache cache;
           
           public MemcachedCache(){
            manager = CacheUtil.getCacheManager(IMemcachedCache.class,
              MemcachedCacheManager.class.getName());
            manager.setConfigFile("memcached.xml");
            manager.setResponseStatInterval(5*1000);
            manager.start();
            cache = manager.getCache("mclient_0");
           }
           
           /**
            * 獲取緩存接口
            * @return
            */
           public IMemcachedCache getCache(){
            return cache;
           }
           
           /**
            * 數(shù)據(jù)放入緩存
            * @param key
            * @param object
            */
           public void put(String key,Object object){
            cache.put(key, object);
           }
           
           /**
            * 從緩存中讀取數(shù)據(jù)
            * @param key
            * @return
            */
           public Object get(String key){
            return cache.get(key);
           }
          }




            五、使用Spring AOP在數(shù)據(jù)查詢的Service層實(shí)現(xiàn)數(shù)據(jù)緩存及讀取

            實(shí)現(xiàn)數(shù)據(jù)緩存的過程很簡單,就是在Service層查詢數(shù)據(jù)庫操作前判斷要查詢的數(shù)據(jù)在緩存中是否存在,如果不存在就到數(shù)據(jù)庫中查詢,查詢完成后將數(shù)據(jù)放入緩存系統(tǒng);如果要查詢的數(shù)據(jù)在緩存中已經(jīng)存在,則直接從緩存中讀取,不需要操作數(shù)據(jù)庫。這就大大降低了數(shù)據(jù)庫的連接次數(shù)。原理就是這么簡單。

            但是,如果直接對Service層代碼進(jìn)行修改,就違背了“開放-封閉”原則,也會導(dǎo)致緩存系統(tǒng)的操作代碼散落到Service層的各處,不方便代碼的管理和維護(hù)。所以,Spring AOP華麗登場了。它使用非入侵式的來創(chuàng)建、管理這些緩存操作代碼。

            關(guān)于Spring AOP本身的一些知識,我們這里不做講述。參考資料:

            由于首先要判斷查詢數(shù)據(jù)是否存在于緩存系統(tǒng),如果存在直接從緩存中讀取,也就是說Service層的查詢代碼根本不會執(zhí)行;另一方面,如果數(shù)據(jù)在緩存系統(tǒng)中不存在,從數(shù)據(jù)庫查詢出的結(jié)果,我們需要將其放入緩存系統(tǒng)中。

            我們來看Spring AOP的幾個(gè)裝備中哪個(gè)適用呢?那就是最強(qiáng)大的環(huán)繞通知裝備@Around!

            下面以UserService為例,其源代碼如下:

          package com.hl.usersmanager.service.impl;

          import java.util.List;

          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.stereotype.Service;
          import org.springframework.transaction.annotation.Transactional;

          import com.hl.usersmanager.dao.IUserMapper;
          import com.hl.usersmanager.model.Users;
          import com.hl.usersmanager.service.IUserService;

          //使用Service注解 不需要再在配置文件中配置bean
          @Service
          public class UserServiceImpl implements IUserService{
           @Autowired
           private IUserMapper userMapper;
           
           @Override
           @Transactional
           public Users findUserByName(String name) {
            return userMapper.findUserByName(name);
           }

           ……
          }

            findUserByName主要實(shí)現(xiàn)按照用戶名查詢用戶的功能,現(xiàn)在我們使用Spring AOP來實(shí)現(xiàn)緩存:

          package com.hl.usersmanager.aop.service;

          import org.apache.log4j.Logger;
          import org.aspectj.lang.ProceedingJoinPoint;
          import org.aspectj.lang.annotation.Around;
          import org.aspectj.lang.annotation.Aspect;
          import org.aspectj.lang.annotation.Pointcut;
          import org.springframework.beans.factory.annotation.Autowired;

          import com.hl.usersmanager.memcached.client.MemcachedCache;
          import com.hl.usersmanager.model.Users;

          @Aspect
          public class UserServiceInterceptor {
           public static final Logger log = Logger
             .getLogger(UserServiceInterceptor.class);

          //將緩存客戶端工具類 MemcachedCache 織入進(jìn)來
           @Autowired
           private MemcachedCache memcachedCache;

           /*
            * 定義pointcunt
            */
           @Pointcut("execution(* com.hl.usersmanager.service.impl.UserServiceImpl.*(..))")
           public void aPointcut() {

           }

           /**
            * 環(huán)繞裝備 用于攔截查詢 如果緩存中有數(shù)據(jù),直接從緩存中讀取;否則從數(shù)據(jù)庫讀取并將結(jié)果放入緩存
            * 
            * @param call
            * @param name
            * @return
            */
           @Around("aPointcut()&&args(name)")
           public Users doFindUserByNameAround(ProceedingJoinPoint call, String name) {
            Users users = null;
            if (memcachedCache.getCache().containsKey("findUserByName_" + name)) {
             users = (Users) memcachedCache.get("findUserByName_" + name);
             log.debug("從緩存中讀取!findUserByName_" + name);
            } else {
             try {
              users = (Users) call.proceed();
              if (users != null) {
               memcachedCache.put("findUserByName_" + name, users);
               log.debug("緩存裝備被執(zhí)行:findUserByName_" + name);
              }
             } catch (Throwable e) {
              e.printStackTrace();
             }
            }
            return users;
           }
          }


           環(huán)繞通知裝備需要一個(gè)ProceedingJoinPoint 類型的參數(shù),它的強(qiáng)大之處在于可以代理一個(gè)我們的切入點(diǎn),指定切入點(diǎn)方法是否執(zhí)行,或者獲取執(zhí)行后的返回結(jié)果!!

            memcachedCache.getCache().containsKey("findUserByName_" + name)

            可以判斷緩存中是否有指定的數(shù)據(jù)。如果有則直接從緩存中讀取:

            users = (Users) memcachedCache.get("findUserByName_" + name);

            否則調(diào)用切入點(diǎn)UserServiceImpl的findUserByName方法:

            users = (Users) call.proceed();

            call.proceed()表示執(zhí)行切入點(diǎn)的方法。

            使用Spring AOP以后,整個(gè)緩存系統(tǒng)代碼看起來 就是這么優(yōu)雅!UserServiceImpl根本不知道外界發(fā)了什么,更不知道外界調(diào)用它的findUserByName的時(shí)候已經(jīng)被攔截了!

            那天不用緩存系統(tǒng),只需要將Aop這塊的代碼去掉即可。

            當(dāng)然,我們還需要在Spring配置文件中注冊一個(gè)memcached客戶端工具類的bean:

          <!-- MemcachedCache緩存 -->
          <bean id="MemcachedCache" class="com.hl.usersmanager.memcached.client.MemcachedCache"></bean>

          posted on 2013-09-11 10:32 順其自然EVO 閱讀(850) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          <2013年9月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 顺义区| 海晏县| 无棣县| 灵璧县| 大连市| 阿图什市| 同心县| 章丘市| 石楼县| 博兴县| 香港| 红安县| 五台县| 无为县| 南乐县| 贵州省| 金寨县| 法库县| 临安市| 睢宁县| 财经| 云龙县| 萍乡市| 彭州市| 沈丘县| 东乡县| 且末县| 仪陇县| 绍兴市| 嘉定区| 霍城县| 莱芜市| 太原市| 贵阳市| 连南| 永修县| 佛山市| 麦盖提县| 招远市| 中卫市| 天祝|