作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
我们来看阶段1,也就是页面缓存阶段,对应的代码:
case DRUPAL_BOOTSTRAP_PAGE_CACHE:
_drupal_bootstrap_page_cache();
break;
Drupal将这个阶段要做的工作,委托给了_drupal_bootstrap_page_cache函数。这个函数也位于bootstrap.inc文件中,我们通过文本查找,很快就找到了这个函数的定义:
/**
* Attempts to serve a page from the cache.
*/
function _drupal_bootstrap_page_cache() {
global $user;
// Allow specifying special cache handlers in settings.php, like
// using memcached or files for storing cache information.
require_once DRUPAL_ROOT . '/includes/cache.inc';
foreach (variable_get('cache_backends', array()) as $include) {
require_once DRUPAL_ROOT . '/' . $include;
}
// Check for a cache mode force from settings.php.
if (variable_get('page_cache_without_database')) {
$cache_enabled = TRUE;
}
else {
drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
$cache_enabled = variable_get('cache');
}
drupal_block_denied(ip_address());
// If there is no session cookie and cache is enabled (or forced), try
// to serve a cached page.
if (!isset($_COOKIE[session_name()]) && $cache_enabled) {
// Make sure there is a user object because its timestamp will be
// checked, hook_boot might check for anonymous user etc.
$user = drupal_anonymous_user();
// Get the page from the cache.
$cache = drupal_page_get_cache();
// If there is a cached page, display it.
if (is_object($cache)) {
header('X-Drupal-Cache: HIT');
// Restore the metadata cached with the page.
$_GET['q'] = $cache->data['path'];
drupal_set_title($cache->data['title'], PASS_THROUGH);
date_default_timezone_set(drupal_get_user_timezone());
// If the skipping of the bootstrap hooks is not enforced, call
// hook_boot.
if (variable_get('page_cache_invoke_hooks', TRUE)) {
bootstrap_invoke_all('boot');
}
drupal_serve_page_from_cache($cache);
// If the skipping of the bootstrap hooks is not enforced, call
// hook_exit.
if (variable_get('page_cache_invoke_hooks', TRUE)) {
bootstrap_invoke_all('exit');
}
// We are done.
exit;
}
else {
header('X-Drupal-Cache: MISS');
}
}
}
很多人经常抱怨Drupal的性能,但是我们看到,在Drupal引导指令的第2个阶段,就支持了页面缓存。这段代码的意思是说,如果存在缓存:
$user = drupal_anonymous_user();
// Get the page from the cache.
$cache = drupal_page_get_cache();
// If there is a cached page, display it.
if (is_object($cache)) {
那么就把缓存页面,返回给客户端:
drupal_serve_page_from_cache($cache);
除此之外,还做了一些其它工作,从缓存中恢复元数据,设置默认时区,当然,(有可能)还触发了两个钩子函数:
bootstrap_invoke_all('boot');
bootstrap_invoke_all('exit');
hook_boot和hook_exit有可能在这里触发。触发钩子函数的途径很多,比如module_invoke_all、module_invoke、drupal_alter、module_implements等等。bootstrap_invoke_all是用来在引导指令阶段就触发钩子函数。
在这个函数里面,我们来看前面几句代码:
require_once DRUPAL_ROOT . '/includes/cache.inc';
foreach (variable_get('cache_backends', array()) as $include) {
require_once DRUPAL_ROOT . '/' . $include;
}
这段代码的含义是,加载includes/cache.inc文件;如果cache_backends不为空的话,那么尝试加载对应include文件。这段代码,我以前很难理解,后来在Drupal实战一书里面,使用memcached模块的时候,才明白这里的用法。我们在使用memcached模块的时候,需要修改settings.php文件,对应的配置如下:
$conf['cache_backends'][] = 'sites/all/modules/memcache/memcache.inc';
$conf['cache_default_class'] = 'MemCacheDrupal';
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';
这里面有$conf['cache_backends'][],它就对应于页面缓存阶段的variable_get('cache_backends'', array())。
我们看到,Drupal与其它缓存技术的集成,是不需要去修改Drupal核心代码的,Drupal核心本身就支持这些潜在的缓存技术。当我们了解到Drupal提供的各种缓存后,我们对于Drupal的性能问题,就没有必要再去担心什么了。