假如我们在写一个基于Spring的普通应用程序,不管我们用了多么精妙的设计模式,进行了如何巧妙的设计,我们必须在某个地方执行这样的代码:
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
appContext.getBean("…");
也许这样的代码算不上丑陋,但是它无疑破坏了程序的纯洁性和透明性。我们的应用程序开始显式地依赖SpringFramework,我们必须清楚地知道Spring的配置文件有哪几个,每个配置文件的加入或修改源代码,我们必须在某些代码模块里调用丑陋的getBean方法来创造对象。
但是所有的这些丑陋的事情似乎在我们的Web应用程序里消失啦,所有的代码都是那么干净,只有简单的get与set及接口之间的调用,我们不需要知道ApplicationContext,我们甚至不需要知道Spring。但是我们所有的对象却又是通过Spring的ApplicationContext来创造的!
看上去似乎很神奇,但是假如我们稍微思考一下,就会发现这是一件合情合理又如此简单的事情,呵呵,只有第一个想到这个方法的人才是伟大的。让我们仔细想一下普通应用程序和Web应用程序的最大区别在哪里?
其实真正的区别只有一个,普通应用程序是一个主动执行的程序,而Web应用程序却是被动的组件。这意味着Web应用程序无法自己主动去生成自己的线程去执行某项任务,而必须借用Web容器中的一个线程。想象一下一个简单的任务:我们想每隔一段时间执行一个任务,比如说在Console里打印出一行文字。在我们的Web应用程序里应该怎么完成?在我不知道Servlet Listener或Spring里提供的Schedule之前(其实Spring就是利用Servlet Listner初始化Application Context时启动schedule的),这么简单的任务在一个Web应用程序里竟然是不可想象。还记得我当时采用的是最傻的做法:写了一个单独的应用程序,在这应用程序的main函数里启动了timetask。
但是如果换一种角度来看,整个Web应用程序生活在容器里也给我们带来了额外的好处,当我们让出了对应用程序的控制权之后,我们可以让容器帮我们完成很多本来很难处理的事情。其实IOC容器的真正作用也在于此,当我们把我们的对象创建工作移交给IOC容器之后,我们发现整个程序变得如此清晰,如此透明,对象之间的关联、哪些类需要事务处理或AOP功能、哪些类要远程访问,所有这些复杂的事情在我们的程序里都不见了,我们只看到了简单的get和set。
也许废话太多,但我觉得经过这样分析,其实ApplicationContext之谜已经不再是谜了。真正的关键在于当我们的Web应用程序是被动的组件时,它除了可以错用容器的线程之外还可以错用其它一些东西。我们可以让容器来帮我们创建ApplicationContext,然后把它放在某个地方,然后在需要使用时让容器从这个地方把ApplicationContext读出来,并执行相应的Controller就可以了。
这个"某个地方"就是ServletContext,而这个创建ApplicationContext的地方就是Servlet Listner,而取到ApplicationContext的地方是我们的DispatcherServlet。
仔细想一下,其实Web服务器并没有什么了不起的地方,它只是一个Java程序,它只是会在启动的时候去ClassLoad某些指定文件夹下的lib或classes,它会读某个在WEB-INF下面一个叫做web.xml的配置文件,再做一些初始化工作。Servlet Listener就是这个初始化工作的重要一步,服务器会读出web.xml里配置好的所有listner,然后调用每个Listner的contextInitialized方法(它还会去调每个Servlet的init方法,不过把初始化方法写在Listner里才是天经地义的)。哈哈,这也正是Spring MVC创建ApplicationContext的最好时机,当我们在web.xml里配置好ContextLoaderListener的时候,Spring就完成了ApplicationContext的创建过程,如果有人想研究源代码的话可以去看一下,不过这个创建过程并不象想象中的那么有趣,只是通过Class.forName和BeanUtils.instantiateClass创建出一个WebApplicationContext,然后再读了一下IOC容器的配置文件。
接下来的一个问题是我们要把创建的ApplicationContext放在哪里?答案是ServletContext,其实没必须对ServletContext进行深究,它只是可以一个可以全局存放Web应用程序的场所,我们只要想象成一个全局的HashMap就可以了,我们可以要把它put进去,就可以在Servlet或其它地方把它get出来。
Web服务器还要干的一件事件当然是在某个request到来时,它会启动一个单独的线程(这也是为何Webwork可以把Context放到ThreadLocal里的原因),根据web.xml里的配置和request的URI匹配去执行相应的Servlet。由于Servlet可以很轻松地读到ServletContext,当然也可以很轻松地读到ApplicationContext啦。接下来的事情就比想象中要简单啦,经过一些准备工作之后ApplicationContext中的URLMapping里配置好的某个Controller,执行一下再rend某个view就可以了。其实struts或webwork2的执行过程也是如此,所以MVC framwork分析透了其实真没什么了不起,远比O/R Mapping或其它的framework简单。虽然MVC的执行过程如此简单,但是我们还需要了解一些细节上的事件,所以让我们下次来讨论一下Spring MVC framework的执行过程吧。
前篇(05-07-11): Spring MVC framework深入分析之一--总体分析
后篇(05-08-05): 评 Head First Design Pattern
最新回复(3件)
| 主题/内容 | 作者/日时 |
|---|---|
|
联系
为为什么不留下联系方式,或是搞个留言板什么的? |
lin
05-08-03 10:24 |
|
乱码
哦,还有,你的文章中有下面一段: |
lin
05-08-03 10:26 |
|
嗯,好奇怪
上次我同学就说有篇文章有乱码,但是我自己看的时候又没发现。不知道是怎么回事,你说的那段乱码我也没看到啊,难到是Itpub的blog有问题 |
xiecc
05-08-05 17:25 |
引用链接
- 您可以按照以下步骤引用本文.本站收到您的引用通知后, 将自动链接您的文章, 以方便别人阅览 .
- 1. 启动您自己的博客管理页面, 并进入发表新文章的画面, 输入文章的内容. (如果您是ITPUB的博客请点这里.)
- 2. 复制下面虚线框里的连接字串, 把它们粘贴到您的文章中, 按照您的喜好修改一下表示文字.
- 3. 确认您选择了"发送引用通知"的选项.
- 4. 发表您的文章.
- 好啦, 您的文章就可以被自动链接到本站啦.
| « | 八月 2008 | » | ||||
|---|---|---|---|---|---|---|
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
| 国内技术blog |
|---|
|
|
|
|
| 国外技术blog |
|---|
|
|
|
|
|
|
|
|
|
|
|
|
| 技术站点 |
|---|
|
|
|
|
| 我的联系方式 |
|---|
|
|
|
|
| 友情链接 |
|---|
|
|
|
|
|
|
| 主页RSS |
|---|
|
|
|
|
|
|
