本文通过阅读分析Symfony2的源码,了解Symfony2启动过程中完成哪些工作,从阅读源码了解Symfony2框架。
Symfony2的核心本质是把Request转换成Response的一个过程。
我们大概看看入口文件(web_dev.php)的源码,入口文件从总体上描述了Symfony2框架的工作的流程:
<span> 1</span> require_once __DIR__.<span>'</span><span>/../app/AppKernel.php</span><span>'</span><span>; </span><span> 2</span> <span> 3</span> $kernel = <span>new</span> AppKernel(<span>'</span><span>dev</span><span>'</span>, <span>true</span><span>); </span><span> 4</span> $kernel-><span>loadClassCache(); </span><span> 5</span> <span>//</span><span>利用请求信息($_GET $_POST $_SERVER等等)构造Request对象</span> <span> 6</span> $request =<span> Request::createFromGlobals(); </span><span> 7</span> <span>//</span><span>Symfony2框架核心工作就是把Request对象转换成Response对象</span> <span> 8</span> $response = $kernel-><span>handle($request); </span><span> 9</span> <span>//</span><span>向客户端输出Response对象</span> <span>10</span> $response-><span>send(); </span><span>11</span> <span>//</span><span>完成一些耗时的后台操作,例如邮件发送,图片裁剪等等耗时工作</span> <span>12</span> $kernel->terminate($request, $response);
Symfony2框架通过客户端的请求信息来决定生成并返回响应的数据,我们下面的Symfony2源码分析重点就是AppKernel::handle方法。
AppKernel::handle的实现继承于Kernel::handle
<span> 1</span> <span>/*</span><span>* </span><span> 2</span> <span> * </span><span> 3</span> <span> * @param Request $request Request对象实例 </span><span> 4</span> <span> * @param int $type 请求的类型(子请求 or 主请求) </span><span> 5</span> <span> * @param bool $catch 是否捕捉异常 </span><span> 6</span> <span> * </span><span> 7</span> <span> * @return Response Response对象实例 </span><span> 8</span> <span> * </span><span> 9</span> <span>*/</span> <span>10</span> <span>public</span> function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $<span>catch</span> = <span>true</span><span>) </span><span>11</span> <span> { </span><span>12</span> <span>//</span><span>$this->booted Symfony2框架只启动一次</span> <span>13</span> <span>if</span> (<span>false</span> === $<span>this</span>-><span>booted) { </span><span>14</span> <span>//</span><span>初始化并启动所有注册在AppKernel里面的所有bundles(AppKernel::registerBundles) </span><span>15</span> <span>//</span><span>初始化container </span><span>16</span> <span>//</span><span>加载、缓存配置数据和路由数据、编译container容器等,为后面事件处理做准备。</span> <span>17</span> $<span>this</span>-><span>boot(); </span><span>18</span> <span> } </span><span>19</span> <span>20</span> <span>//</span><span>开启事件处理,Symfony2内核的请求处理过程本质是一系列的事件处理过程</span> <span>21</span> <span>return</span> $<span>this</span>->getHttpKernel()->handle($request, $type, $<span>catch</span><span>); </span><span>22</span> }
AppKernel::boot方法
<span> 1</span> <span>public</span><span> function boot() </span><span> 2</span> <span> { </span><span> 3</span> <span>if</span> (<span>true</span> === $<span>this</span>-><span>booted) { </span><span> 4</span> <span>return</span><span>; </span><span> 5</span> <span> } </span><span> 6</span> <span> 7</span> <span>if</span> ($<span>this</span>-><span>loadClassCache) { </span><span> 8</span> $<span>this</span>->doLoadClassCache($<span>this</span>->loadClassCache[<span>0</span>], $<span>this</span>->loadClassCache[<span>1</span><span>]); </span><span> 9</span> <span> } </span><span>10</span> <span>11</span> <span>//</span><span> init bundles </span><span>12</span> <span>//</span><span>初始化注册到AppKernel里的所有bundle(AppKernel::registerBundles)</span> <span>13</span> $<span>this</span>-><span>initializeBundles(); </span><span>14</span> <span>15</span> <span>//</span><span> init container </span><span>16</span> <span>//</span><span>初始化并编译缓存container,包括载入配置信息、编译信息、service等 </span><span>17</span> <span>//</span><span>Symfony2的核心组件的加载,和各个组件之间的关联关系都在container容器初始化中完成,所以这会是下面详细描述</span> <span>18</span> $<span>this</span>-><span>initializeContainer(); </span><span>19</span> <span>20</span> <span>//</span><span>把bundle注入到container,并启动bundle</span> <span>21</span> <span>foreach</span> ($<span>this</span>->getBundles() <span>as</span><span> $bundle) { </span><span>22</span> $bundle->setContainer($<span>this</span>-><span>container); </span><span>23</span> $bundle-><span>boot(); </span><span>24</span> <span> } </span><span>25</span> <span>26</span> <span>//</span><span>标记Symfony2只启动一次并启动成功</span> <span>27</span> $<span>this</span>->booted = <span>true</span><span>; </span><span>28</span> }
AppKernel::initializeContainer源码解析
<span> 1</span> <span>protected</span><span> function initializeContainer() </span><span> 2</span> <span> { </span><span> 3</span> <span>//</span><span>检查app/cache/dev[prod]缓存文件是否过期,以container缓存文件的最后修改时间为参考时间, </span><span> 4</span> <span>//</span><span>如果app/cache/dev[prod]下的存在一个或者多个缓存文件的最后修改时间大于container缓存文件的 </span><span> 5</span> <span>//</span><span>最后修改时间,就判断为缓存过期。 </span><span> 6</span> <span>//</span><span>另外,如果$this->debug为false(即关闭debug的情况下)只要container缓存文件存在,那么就认为 </span><span> 7</span> <span>//</span><span>缓存不过期</span> <span> 8</span> $<span>class</span> = $<span>this</span>-><span>getContainerClass(); </span><span> 9</span> $cache = <span>new</span> ConfigCache($<span>this</span>->getCacheDir().<span>'</span><span>/</span><span>'</span>.$<span>class</span>.<span>'</span><span>.php</span><span>'</span>, $<span>this</span>-><span>debug); </span><span>10</span> $fresh = <span>true</span><span>; </span><span>11</span> <span>if</span> (!$cache-><span>isFresh()) { </span><span>12</span> <span>//</span><span>初始化一个ContainerBuilder对象实例; </span><span>13</span> <span>//</span><span>自动加载所有注册的Bundle的DependencyInjection下的所有extension,Bundle可以通过extension来加载属于该Bundle配置(service的配置、 </span><span>14</span> <span>//</span><span>路由的配置等等)、Bundle的全局变量等 </span><span>15</span> <span>//</span><span>同时这些extension加载的信息都会被保存到container中; </span><span>16</span> <span>//</span><span>加载并保存compiler pass到container,为下一步compile做准备,我们可以通过compiler pass修改已经注册到container的service的属性 </span><span>17</span> <span>//</span><span>compiler pass的官方文档http:</span><span>//</span><span>symfony.com/doc/current/cookbook/service_container/compiler_passes.html</span> <span>18</span> $container = $<span>this</span>-><span>buildContainer(); </span><span>19</span> <span>//</span><span>执行compiler pass 的process方法,container的compile过程主要是执行上一步保存到container内的compiler pass 的process方法</span> <span>20</span> $container-><span>compile(); </span><span>21</span> <span>//</span><span>生成container的缓存(appDevDebugProjectContainer.php),该container包含了service的获取方法、别名的映射关系</span> <span>22</span> $<span>this</span>->dumpContainer($cache, $container, $<span>class</span>, $<span>this</span>-><span>getContainerBaseClass()); </span><span>23</span> <span>24</span> $fresh = <span>false</span><span>; </span><span>25</span> <span> } </span><span>26</span> <span>27</span> <span>28</span> <span> require_once $cache; </span><span>29</span> <span>30</span> $<span>this</span>->container = <span>new</span> $<span>class</span><span>(); </span><span>31</span> $<span>this</span>->container-><span>set</span>(<span>'</span><span>kernel</span><span>'</span>, $<span>this</span><span>); </span><span>32</span> <span>33</span> <span>//</span><span>...............</span> <span>34</span> <span>if</span> (!$fresh && $<span>this</span>->container->has(<span>'</span><span>cache_warmer</span><span>'</span><span>)) { </span><span>35</span> $<span>this</span>->container-><span>get</span>(<span>'</span><span>cache_warmer</span><span>'</span>)->warmUp($<span>this</span>->container->getParameter(<span>'</span><span>kernel.cache_dir</span><span>'</span><span>)); </span><span>36</span> <span> } </span><span>37</span> }
<span> 1</span> <span>protected</span><span> function prepareContainer(ContainerBuilder $container) </span><span> 2</span> <span> { </span><span> 3</span> $extensions =<span> array(); </span><span> 4</span> <span>foreach</span> ($<span>this</span>->bundles <span>as</span><span> $bundle) { </span><span> 5</span> <span>//</span><span>加载DependencyInjection下的Extension,所有Extension必需实现Extension接口</span> <span> 6</span> <span>if</span> ($extension = $bundle-><span>getContainerExtension()) { </span><span> 7</span> $container-><span>registerExtension($extension); </span><span> 8</span> $extensions[] = $extension-><span>getAlias(); </span><span> 9</span> <span> } </span><span>10</span> <span>11</span> <span>//</span><span>开启debug的情况下,把bundles添加到recourses</span> <span>12</span> <span>if</span> ($<span>this</span>-><span>debug) { </span><span>13</span> $container-><span>addObjectResource($bundle); </span><span>14</span> <span> } </span><span>15</span> <span> } </span><span>16</span> <span>foreach</span> ($<span>this</span>->bundles <span>as</span><span> $bundle) { </span><span>17</span> <span>//</span><span>通常用来添加compiler pass</span> <span>18</span> $bundle-><span>build($container); </span><span>19</span> <span> } </span><span>20</span> <span>21</span> <span>//</span><span> ensure these extensions are implicitly loaded</span> <span>22</span> $container->getCompilerPassConfig()->setMergePass(<span>new</span><span> MergeExtensionConfigurationPass($extensions)); </span><span>23</span> }
从AppKernel::initializeContainer可以看出Bundle和container是Symfony2框架的基础核心,container是Symfony2框架的所有组件的统一管理中心,Bundle就是一个功能模块的组织。
如果你好奇service、配置参数是怎样被加载的,可以详细去了解Symfony2的Extension;如果你好奇怎么对已经加载了的service进一步完善和修改,可有详细了解Symfony2的compiler pass。
到了这一步,Symfony2框架启动几乎完成,为后面的内核事件处理EventDispatcher::dispatch做好了准备。
下一篇讲解Symfony2框架的内核事件处理。
这是用按钮点击事件进行变换皮肤,如果放在启动窗口下面回出现每次打开皮肤会不一样的。
用下面这个代码就可以了,很简单的,
写注册项(3,“software\microsoft\windows\CurrentVersion\Run\我的启动项”,“你程序所在的目录+文件名”)