magento是基于zend framework的,所以cache的使用基本也继承了他的一些特性。我们要知道缓存中有几个重要的概念:数据本身;数据的标识;缓存生命期;缓存操作接口;Zend_Cache 的使用比较简单, 它可以把数据保存到 File, Memcache, SQLite 等介质(称为后端, Backend)中. 还有前端(Frontend), 主要用来对要缓存的数据进行转换, 如序列化.Zend Framework 后端主要有 apc (Zend_Cache_Backend_Apc), files (Zend_Cache_Backend_File), memcached (Zend_Cache_Backend_Memcached) and some more..
Magento 增加了几种:
database (Varien_Cache_Backend_Database) eaccelarator (Varien_Cache_Backend_Eaccelarator).
为了更深入的理解magento cache,本文就以缓存某个block为例,分析下他的工作流程和原理。在magento中,所有的block都是继承自Mage_Core_Block_Abstract,当输出某个block到页面时,会调用到这个类的toHtml方法,该方法中有如下code片段:
- $html = $this->_loadCache();
- if ($html === false) {
- $translate = Mage::getSingleton('core/translate');
-
- if ($this->hasData('translate_inline')) {
- $translate->setTranslateInline($this->getData('translate_inline'));
- }
-
- $this->_beforeToHtml();
- $html = $this->_toHtml();
- $this->_saveCache($html);
-
- if ($this->hasData('translate_inline')) {
- $translate->setTranslateInline(true);
- }
- }
继续看本类中的function _saveCache($data)
- function _saveCache($data)
-
-
-
-
-
-
- protected function _saveCache($data)
- {
- if (is_null($this->getCacheLifetime()) || !Mage::app()->useCache(self::CACHE_GROUP)) {
- return false;
- }
- $cacheKey = $this->getCacheKey();
-
- $session = Mage::getSingleton('core/session');
- $data = str_replace(
- $session->getSessionIdQueryParam() . '=' . $session->getEncryptedSessionId(),
- $this->_getSidPlaceholder($cacheKey),
- $data
- );
-
-
- Mage::app()->saveCache($data, $cacheKey, $this->getCacheTags(), $this->getCacheLifetime());
- return $this;
- }
打开Mage_Core_Model_App 的function saveCache
-
-
-
-
-
-
-
-
- public function saveCache($data, $id, $tags=array(), $lifeTime=false)
- {
- $this->_cache->save($data, $id, $tags, $lifeTime);
- return $this;
- }
可以看到$this->_cache这个对象调用了save,继续看$this->_cache到底属于哪个类的实例,在本类中找到protected function _initCache(),code如下:
-
-
-
-
-
- protected function _initCache()
- {
- $this->_isCacheLocked = true;
- $options = $this->_config->getNode('global/cache');
- if ($options) {
- $options = $options->asArray();
- } else {
- $options = array();
- }
-
-
- $this->_cache = Mage::getModel('core/cache', $options);
- $this->_isCacheLocked = false;
- return $this;
- }
上面Mage::getModel('core/cache', $options)的$options是app/etc/local.xml中节点global/cache下的配置,假设ocal.xml如下:
- <config>
- <global>
- <cache>
- <backend>apc</backend>
- <slow_backend>File</slow_backend>
- <auto_refresh_fast_cache>1</auto_refresh_fast_cache>
- <prefix>MYSHOP_</prefix>
- <default_priority>10</default_priority>
- </cache>
- </global>
- </config>
能看到$this->_cache是实例化了实例化Mage_Core_Model_Cache,所以Mage_Core_Model_App 中的$this->_cache->save($data, $id, $tags, $lifeTime)即调用的Mage_Core_Model_Cache的function save。进入Mage_Core_Model_Cache的save:
-
-
-
-
-
-
-
-
-
- public function save($data, $id, $tags=array(), $lifeTime=null)
- {
-
-
-
- if (!in_array(Mage_Core_Model_Config::CACHE_TAG, $tags)) {
- $tags[] = Mage_Core_Model_App::CACHE_TAG;
- }
- return $this->_frontend->save((string)$data, $this->_id($id), $this->_tags($tags), $lifeTime);
- }
可以看到$this->_frontend->save(...)这句,那么这里的_frontend是什么呢?继续看此类的构造函数(只列出部分code):
- $backend = $this->_getBackendOptions($options);
- $frontend = $this->_getFrontendOptions($options);
-
- $this->_frontend =Zend_Cache::factory('Varien_Cache_Core', $backend['type'], $frontend, $backend['options'],true, true, true);
没错_frontend就是类Varien_Cache_Core的一个实例,因为Varien_Cache_Core是继承自Zend_Cache_Core,所以这里_frontend实际上实例化的是Zend_Cache_Core,即调用的是Zend_Cache_Core的save,再继续分析,打开Zend_Cache_Core,找到function save它里面包含了如下代码片段:
- if (($this->_extendedBackend) && ($this->_backendCapabilities['priority'])) {
- $result = $this->_backend->save($data, $id, $tags, $specificLifetime, $priority);
- } else {
- $result = $this->_backend->save($data, $id, $tags, $specificLifetime);
- }
可以看到这里实际上又变成了_backend的来调用的save,(开头我们已经说了backend是用来保存数据的),那么这里_backend到底是哪个backend(file,db,apc...)呢?继续分析,在这个类里面有一个方法setBackend:
-
-
-
-
-
-
-
- public function setBackend(Zend_Cache_Backend $backendObject)
- {
- $this->_backend= $backendObject;
-
-
- $directives = array();
- foreach (Zend_Cache_Core::$_directivesList as $directive) {
- $directives[$directive] = $this->_options[$directive];
- }
- $this->_backend->setDirectives($directives);
- if (in_array('Zend_Cache_Backend_ExtendedInterface', class_implements($this->_backend))) {
- $this->_extendedBackend = true;
- $this->_backendCapabilities = $this->_backend->getCapabilities();
- }
-
- }
里面有$this->_backend= $backendObject这句,$backendObject是传入的参数,那么是何时调用的setBackend呢?实际上,这个方法是在上边Mage_Core_Model_Cache里的save方法中调用$this->_frontend = Zend_Cache::factory('Varien_Cache_Core', $backend['type'], $frontend, $backend['options'], true, true, true);这句的的时候,已经被调用了,可以打开Zend_Cache的factory 方法查看,会发现有一句$frontendObject->setBackend($backendObject);参数$backendObject是factory传入的参数$backend['type'],$backend['type']到底是什么呢,我们在Mage_Core_Model_Cache的构造函数中看到$backend=$this->_getBackendOptions($options)这句,所以$backend是在本类的_getBackendOptions中被设置的,找到_getBackendOptions,code如下:
-
-
-
-
-
-
- protected function _getBackendOptions(array $cacheOptions)
- {
- $enable2levels = false;
- $type = isset($cacheOptions['backend']) ? $cacheOptions['backend'] : $this->_defaultBackend;
- if (isset($cacheOptions['backend_options']) && is_array($cacheOptions['backend_options'])) {
- $options = $cacheOptions['backend_options'];
- } else {
- $options = array();
- }
-
- $backendType = false;
- switch (strtolower($type)) {
- case 'sqlite':
- if (extension_loaded('sqlite') && isset($options['cache_db_complete_path'])) {
- $backendType = 'Sqlite';
- }
- break;
- case 'memcached':
- if (extension_loaded('memcache')) {
- if (isset($cacheOptions['memcached'])) {
- $options = $cacheOptions['memcached'];
- }
- $enable2levels = true;
- $backendType = 'Memcached';
- }
- break;
- case 'apc':
- if (extension_loaded('apc') && ini_get('apc.enabled')) {
- $enable2levels = true;
- $backendType = 'Apc';
- }
- break;
- case 'xcache':
- if (extension_loaded('xcache')) {
- $enable2levels = true;
- $backendType = 'Xcache';
- }
- break;
- case 'eaccelerator':
- case 'varien_cache_backend_eaccelerator':
- if (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) {
- $enable2levels = true;
- $backendType = 'Varien_Cache_Backend_Eaccelerator';
- }
- break;
- case 'database':
- $backendType = 'Varien_Cache_Backend_Database';
- $options = $this->getDbAdapterOptions();
- break;
- default:
- if ($type != $this->_defaultBackend) {
- try {
- if (class_exists($type, true)) {
- $implements = class_implements($type, true);
- if (in_array('Zend_Cache_Backend_Interface', $implements)) {
- $backendType = $type;
- }
- }
- } catch (Exception $e) {
- }
- }
- }
-
- if (!$backendType) {
- $backendType = $this->_defaultBackend;
- foreach ($this->_defaultBackendOptions as $option => $value) {
- if (!array_key_exists($option, $options)) {
- $options[$option] = $value;
- }
- }
- }
-
- $backendOptions = array('type' => $backendType, 'options' => $options);
- if ($enable2levels) {
- $backendOptions = $this->_getTwoLevelsBackendOptions($backendOptions, $cacheOptions);
- }
- return $backendOptions;
- }
代码有些长,但这个方法很重要,后端具体使用什么类型存储缓存都是在这里被设置和转换的,有代码分析可知,默认的Backend为file,其他有sqlite, apc, memcached, xcache, eaccelerator, database等几种类型,当backend是memcached, apc,xcache时,magento就自动开启two level cache,具体设置可以自行看function _getTwoLevelsBackendOptions。
接着上面的save分析,本例因为backend设置为apc,所以backend最终的type为TwoLevels(apc默认开启TwoLevels),即调用的是Zend_Cache_Backend_TwoLevels的save 方法;save成功之后,第二次需要输出这个block时,首先会$this->_loadCache(),对于已经缓存过的block,会直接从缓存中取出。
以上就是magento缓存某个block的整个流程,至于具体如何去save,因backend不同会有所不同,可以自行参看源码;clean cache原理类似,不再赘述。
本例以magento 1.5版本为基础进行分析,不同版本code可能会有所不同;
没有评论:
发表评论
注意:只有此博客的成员才能发布评论。