`
javawl
  • 浏览: 28068 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Spring源码分析(转)

 
阅读更多

在认真学习Rod.Johnson的三部曲之一:<<Professional Java Development with the spring framework>>,顺便也看了看源代码想知道个究竟,抛砖引玉,有兴趣的同志一起讨论研究吧!
 在Spring中,IOC容器的重要地位我们就不多说了,对于Spring的使用者而言,IOC容器实际上是什么呢?我们可以说BeanFactory就 是我们看到的IoC容器,当然了Spring为我们准备了许多种IoC容器来使用,这样可以方便我们从不同的层面,不同的资源位置,不同的形式的定义信息 来建立我们需要的IoC容器。
 在Spring中,最基本的IOC容器接口是BeanFactory – 这个接口为具体的IOC容器的实现作了最基本的功能规定 – 不管怎么着,作为IOC容器,这些接口你必须要满足应用程序的最基本要求:
  

Java代码 

public interface BeanFactory {   

  

    //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,  

    //如果需要得到工厂本身,需要转义         

    String FACTORY_BEAN_PREFIX = "&";   

  

  

    //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。  

    Object getBean(String name) throws BeansException;   

10   

11     //这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。  

12     Object getBean(String name, Class requiredType) throws BeansException;   

13   

14     //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean  

15     boolean containsBean(String name);   

16   

17     //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件  

18     boolean isSingleton(String name) throws NoSuchBeanDefinitionException;   

19   

20     //这里对得到bean实例的Class类型  

21     Class getType(String name) throws NoSuchBeanDefinitionException;   

22   

23     //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来  

24     String[] getAliases(String name);   

25   

26 }  

27 public interface BeanFactory {  

28   

29     //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,  

30     //如果需要得到工厂本身,需要转义  

31     String FACTORY_BEAN_PREFIX = "&";  

32   

33     //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。  

34     Object getBean(String name) throws BeansException;  

35   

36     //这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。  

37     Object getBean(String name, Class requiredType) throws BeansException;  

38   

39     //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean  

40     boolean containsBean(String name);  

41   

42     //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件  

43     boolean isSingleton(String name) throws NoSuchBeanDefinitionException;  

44   

45     //这里对得到bean实例的Class类型  

46     Class getType(String name) throws NoSuchBeanDefinitionException;  

47   

48     //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来  

49     String[] getAliases(String name);  

50   

51 }  

BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是怎样定义怎样加载的 – 就像我们只关心从这个工厂里我们得到到什么产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心这些。如果要关心工厂是怎样产生对象的,应用程 序需要使用具体的IOC容器实现当然你可以自己根据这个BeanFactory来实现自己的IOC容器,但这个没有必要,因为Spring已经为我们准备好了一系列工厂来让我们使用。比 如XmlBeanFactory就是针对最基础的BeanFactoryIOC容器的实现 – 这个实现使用xml来定义IOC容器中的bean
 Spring提供了一个BeanFactory的基本实现,XmlBeanFactory同样的通过使用模板模式来得到对IOC容器的抽象- AbstractBeanFactory,DefaultListableBeanFactory这些抽象类为其提供模板服务。其中通过resource 接口来抽象bean定义数据,对Xml定义文件的解析通过委托给XmlBeanDefinitionReader来完成。下面我们根据书上的例子,简单的 演示IOC容器的创建过程:
  

Java代码 

52 ClassPathResource res = new ClassPathResource("beans.xml");   

53 DefaultListableBeanFactory factory = new DefaultListableBeanFactory();   

54 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);   

55 reader.loadBeanDefinitions(res);  

56 ClassPathResource res = new ClassPathResource("beans.xml");  

57 DefaultListableBeanFactory factory = new DefaultListableBeanFactory();  

58 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);  

59 reader.loadBeanDefinitions(res);  

这些代码演示了以下几个步骤:

   1. 创建IOC配置文件的抽象资源
    2. 创建一个BeanFactory
    3. 把读取配置信息的BeanDefinitionReader,这里是XmlBeanDefinitionReader配置给BeanFactory
    4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成,这样完成整个载入bean定义的过程。我们的IoC容器就建立起来了。在BeanFactory的源代码中我们可以看到:
  

Java代码 

60 public class XmlBeanFactory extends DefaultListableBeanFactory {   

61     //这里为容器定义了一个默认使用的bean定义读取器  

62     private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);   

63     public XmlBeanFactory(Resource resource) throws BeansException {   

64         this(resource, null);   

65     }   

66     //在初始化函数中使用读取器来对资源进行读取,得到bean定义信息。  

67     public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {   

68         super(parentBeanFactory);   

69         this.reader.loadBeanDefinitions(resource);   

70     }  

71 public class XmlBeanFactory extends DefaultListableBeanFactory {  

72     //这里为容器定义了一个默认使用的bean定义读取器  

73     private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);  

74     public XmlBeanFactory(Resource resource) throws BeansException {  

75         this(resource, null);  

76     }  

77     //在初始化函数中使用读取器来对资源进行读取,得到bean定义信息。  

78     public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {  

79         super(parentBeanFactory);  

80         this.reader.loadBeanDefinitions(resource);  

81     }  

我们在后面会看到读取器读取资源和注册bean定义信息的整个过程,基本上是和上下文的处理是一样的,从这里我们可以看到上下文和 XmlBeanFactory这两种IOC容器的区别,BeanFactory往往不具备对资源定义的能力,而上下文可以自己完成资源定义,从这个角度上 看上下文更好用一些。
 仔细分析Spring BeanFactory的结构,我们来看看在BeanFactory基础上扩展出的ApplicationContext – 我们最常使用的上下文。除了具备BeanFactory的全部能力,上下文为应用程序又增添了许多便利:

    * 可以支持不同的信息源,我们看到ApplicationContext扩展了MessageSource
     * 访问资源 体现在对ResourceLoaderResource的支持上面,这样我们可以从不同地方得到bean定义资源
     * 支持应用事件,继承了接口ApplicationEventPublisher,这样在上下文中引入了事件机制而BeanFactory是没有的。

ApplicationContext允许上下文嵌套 – 通过保持父上下文可以维持一个上下文体系 – 这个体系我们在以后对Web容器中的上下文环境的分析中可以清楚地看到。对于bean的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上 下文,逐级向上,这样为不同的Spring应用提供了一个共享的bean定义环境。这个我们在分析Web容器中的上下文环境时也能看到。
 ApplicationContext提供IoC容器的主要接口,在其体系中有许多抽象子类比如AbstractApplicationContext为 具体的BeanFactory的实现,比如FileSystemXmlApplicationContext和 ClassPathXmlApplicationContext提供上下文的模板,使得他们只需要关心具体的资源定位问题。当应用程序代码实例化 FileSystemXmlApplicationContext的时候,得到IoC容器的一种具体表现 – ApplicationContext,从而应用程序通过ApplicationContext来管理对bean的操作。
 BeanFactory 是一个接口,在实际应用中我们一般使用ApplicationContext来使用IOC容器,它们也是IOC容器展现给应用开发者的使用接口。对应用程 序开发者来说,可以认为BeanFactoryApplicationFactory在不同的使用层面上代表了SPRING提供的IOC容器服务。
 下面我们具体看看通过FileSystemXmlApplicationContext是怎样建立起IOC容器的显而易见我们可以通过new来得到IoC容器:
  

Java代码 

82 ApplicationContext = new FileSystemXmlApplicationContext(xmlPath);  

83 ApplicationContext = new FileSystemXmlApplicationContext(xmlPath);  

调用的是它初始化代码:
  

Java代码 

84 public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)   

85         throws BeansException {   

86     super(parent);   

87     this.configLocations = configLocations;   

88     if (refresh) {   

89        //这里是IoC容器的初始化过程,其初始化过程的大致步骤由AbstractApplicationContext来定义  

90         refresh();   

91     }   

92 }  

93 public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  

94         throws BeansException {  

95     super(parent);  

96     this.configLocations = configLocations;  

97     if (refresh) {  

98        //这里是IoC容器的初始化过程,其初始化过程的大致步骤由AbstractApplicationContext来定义  

99         refresh();  

100     }  

101 }  

refresh的模板在AbstractApplicationContext:
  

Java代码 

102 public void refresh() throws BeansException, IllegalStateException {   

103     synchronized (this.startupShutdownMonitor) {   

104         synchronized (this.activeMonitor) {   

105             this.active = true;   

106         }   

107   

108         // 这里需要子类来协助完成资源位置定义,bean载入和向IOC容器注册的过程  

109         refreshBeanFactory();   

110         …………   

111  }  

112 public void refresh() throws BeansException, IllegalStateException {  

113     synchronized (this.startupShutdownMonitor) {  

114         synchronized (this.activeMonitor) {  

115             this.active = true;  

116         }  

117   

118         // 这里需要子类来协助完成资源位置定义,bean载入和向IOC容器注册的过程  

119         refreshBeanFactory();  

120         ............  

121  }  

这个方法包含了整个BeanFactory初始化的过程,对于特定的FileSystemXmlBeanFactory,我们看到定位资源位置由refreshBeanFactory()来实现:
 在AbstractXmlApplicationContext中定义了对资源的读取过程,默认由XmlBeanDefinitionReader来读取:
  

Java代码 

122 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {   

123     // 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件  

124     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);   

125   

126     //这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的  

127     ///因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader  

128     beanDefinitionReader.setResourceLoader(this);   

129     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));   

130   

131     initBeanDefinitionReader(beanDefinitionReader);   

132     //这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理  

133     loadBeanDefinitions(beanDefinitionReader);   

134 }  

135 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {  

136     // 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件  

137     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  

138   

139     //这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的  

140     ///因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader  

141     beanDefinitionReader.setResourceLoader(this);  

142     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  

143   

144     initBeanDefinitionReader(beanDefinitionReader);  

145     //这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理  

146     loadBeanDefinitions(beanDefinitionReader);  

147 }  

转到beanDefinitionReader中进行处理:
  

Java代码 

148 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {   

149     Resource[] configResources = getConfigResources();   

150     if (configResources != null) {   

151         //调用XmlBeanDefinitionReader来载入bean定义信息。  

152         reader.loadBeanDefinitions(configResources);   

153     }   

154     String[] configLocations = getConfigLocations();   

155     if (configLocations != null) {   

156         reader.loadBeanDefinitions(configLocations);   

157     }   

158 }  

159 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  

160     Resource[] configResources = getConfigResources();  

161     if (configResources != null) {  

162         //调用XmlBeanDefinitionReader来载入bean定义信息。  

163         reader.loadBeanDefinitions(configResources);  

164     }  

165     String[] configLocations = getConfigLocations();  

166     if (configLocations != null) {  

167         reader.loadBeanDefinitions(configLocations);  

168     }  

169 }  

而在作为其抽象父类的AbstractBeanDefinitionReader中来定义载入过程:
  

Java代码 

170 public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {   

171  //这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader  

172  ResourceLoader resourceLoader = getResourceLoader();   

173  ………//如果没有找到我们需要的ResourceLoader,直接抛出异常  

174     if (resourceLoader instanceof ResourcePatternResolver) {   

175         // 这里处理我们在定义位置时使用的各种pattern,需要ResourcePatternResolver来完成  

176         try {   

177             Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);   

178             int loadCount = loadBeanDefinitions(resources);   

179             return loadCount;   

180         }   

181       ……..   

182     }   

183     else {   

184         // 这里通过ResourceLoader来完成位置定位  

185         Resource resource = resourceLoader.getResource(location);   

186         // 这里已经把一个位置定义转化为Resource接口,可以供XmlBeanDefinitionReader来使用了  

187         int loadCount = loadBeanDefinitions(resource);   

188         return loadCount;   

189     }   

190 }  

191 public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {  

192  //这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader  

193  ResourceLoader resourceLoader = getResourceLoader();  

194  .........//如果没有找到我们需要的ResourceLoader,直接抛出异常  

195     if (resourceLoader instanceof ResourcePatternResolver) {  

196         // 这里处理我们在定义位置时使用的各种pattern,需要ResourcePatternResolver来完成  

197         try {  

198             Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);  

199             int loadCount = loadBeanDefinitions(resources);  

200             return loadCount;  

201         }  

202       ........  

203     }  

204     else {  

205         // 这里通过ResourceLoader来完成位置定位  

206         Resource resource = resourceLoader.getResource(location);  

207         // 这里已经把一个位置定义转化为Resource接口,可以供XmlBeanDefinitionReader来使用了  

208         int loadCount = loadBeanDefinitions(resource);  

209         return loadCount;  

210     }  

211 }  

当我们通过ResourceLoader来载入资源,别忘了了我们的GenericApplicationContext也实现了ResourceLoader接口:
  

Java代码 

212 public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {   

213     public Resource getResource(String location) {   

214         //这里调用当前的loader也就是DefaultResourceLoader来完成载入  

215         if (this.resourceLoader != null) {   

216             return this.resourceLoader.getResource(location);   

217         }   

218         return super.getResource(location);   

219     }   

220 …….   

221 }  

222 public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {  

223     public Resource getResource(String location) {  

224         //这里调用当前的loader也就是DefaultResourceLoader来完成载入  

225         if (this.resourceLoader != null) {  

226             return this.resourceLoader.getResource(location);  

227         }  

228         return super.getResource(location);  

229     }  

230 .......  

231 }  

而我们的FileSystemXmlApplicationContext就是一个DefaultResourceLoader – GenericApplicationContext()通过DefaultResourceLoader:
  

Java代码 

232 public Resource getResource(String location) {   

233     //如果是类路径的方式,那需要使用ClassPathResource来得到bean文件的资源对象  

234     if (location.startsWith(CLASSPATH_URL_PREFIX)) {   

235         return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());   

236     }   

237     else {   

238         try {   

239             // 如果是URL方式,使用UrlResource作为bean文件的资源对象  

240             URL url = new URL(location);   

241             return new UrlResource(url);   

242         }   

243         catch (MalformedURLException ex) {   

244             // 如果都不是,那我们只能委托给子类由子类来决定使用什么样的资源对象了  

245             return getResourceByPath(location);   

246         }   

247     }   

248 }  

249 public Resource getResource(String location) {  

250     //如果是类路径的方式,那需要使用ClassPathResource来得到bean文件的资源对象  

251     if (location.startsWith(CLASSPATH_URL_PREFIX)) {  

252         return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());  

253     }  

254     else {  

255         try {  

256             // 如果是URL方式,使用UrlResource作为bean文件的资源对象  

257             URL url = new URL(location);  

258             return new UrlResource(url);  

259         }  

260         catch (MalformedURLException ex) {  

261             // 如果都不是,那我们只能委托给子类由子类来决定使用什么样的资源对象了  

262             return getResourceByPath(location);  

263         }  

264     }  

265 }  

我们的FileSystemXmlApplicationContext本身就是是DefaultResourceLoader的实现类,他实现了以下的接口:
  

Java代码 

266 protected Resource getResourceByPath(String path) {   

267     if (path != null && path.startsWith("/")) {   

268         path = path.substring(1);   

269     }   

270     //这里使用文件系统资源对象来定义bean文件  

271     return new FileSystemResource(path);   

272 }  

273 protected Resource getResourceByPath(String path) {  

274     if (path != null && path.startsWith("/")) {  

275         path = path.substring(1);  

276     }  

277     //这里使用文件系统资源对象来定义bean文件  

278     return new FileSystemResource(path);  

279 }  

这样代码就回到了FileSystemXmlApplicationContext中来,他提供了FileSystemResource来完成从文件系统 得到配置文件的资源定义。这样,就可以从文件系统路径上对IOC配置文件进行加载 – 当然我们可以按照这个逻辑从任何地方加载,在Spring中我们看到它提供的各种资源抽象,比如ClassPathResource, URLResource,FileSystemResource等来供我们使用。上面我们看到的是定位Resource的一个过程,而这只是加载过程的一 部分 – 我们回到AbstractBeanDefinitionReaderz中的loadDefinitions(resource)来看看得到代表bean文 件的资源定义以后的载入过程,默认的我们使用XmlBeanDefinitionReader
  

Java代码 

280 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {   

281     …….   

282     try {   

283         //这里通过Resource得到InputStreamIO  

284         InputStream inputStream = encodedResource.getResource().getInputStream();   

285         try {   

286             //InputStream中得到XML的解析源  

287             InputSource inputSource = new InputSource(inputStream);   

288             if (encodedResource.getEncoding() != null) {   

289                 inputSource.setEncoding(encodedResource.getEncoding());   

290             }   

291             //这里是具体的解析和注册过程  

292             return doLoadBeanDefinitions(inputSource, encodedResource.getResource());   

293         }   

294         finally {   

295             //关闭从Resource中得到的IO  

296             inputStream.close();   

297         }   

298     }   

299        ………   

300 }   

301   

302 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)   

303         throws BeanDefinitionStoreException {   

304     try {   

305         int validationMode = getValidationModeForResource(resource);   

306         //通过解析得到DOM,然后完成beanIOC容器中的注册  

307         Document doc = this.documentLoader.loadDocument(   

308                 inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);   

309         return registerBeanDefinitions(doc, resource);   

310     }   

311 …….   

312 }  

313 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {  

314     .......  

315     try {  

316         //这里通过Resource得到InputStreamIO流  

317         InputStream inputStream = encodedResource.getResource().getInputStream();  

318         try {  

319             //InputStream中得到XML的解析源  

320             InputSource inputSource = new InputSource(inputStream);  

321             if (encodedResource.getEncoding() != null) {  

322                 inputSource.setEncoding(encodedResource.getEncoding());  

323             }  

324             //这里是具体的解析和注册过程  

325             return doLoadBeanDefinitions(inputSource, encodedResource.getResource());  

326         }  

327         finally {  

328             //关闭从Resource中得到的IO流  

329             inputStream.close();  

330         }  

331     }  

332        .........  

333 }  

334   

335 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  

336         throws BeanDefinitionStoreException {  

337     try {  

338         int validationMode = getValidationModeForResource(resource);  

339         //通过解析得到DOM,然后完成beanIOC容器中的注册  

340         Document doc = this.documentLoader.loadDocument(  

341                 inputSource, this.entityResolver, this.errorHandler, validationMode, <a href="http://this.name" title="http://this.name" target="_blank">this.name</a>spaceAware);  

342         return registerBeanDefinitions(doc, resource);  

343     }  

344 .......  

345 }  

我们看到先把定义文件解析为DOM对象,然后进行具体的注册过程:
  

Java代码 

346 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {   

347     // 这里定义解析器,使用XmlBeanDefinitionParser来解析xml方式的bean定义文件 现在的版本不用这个解析器了,使用的是XmlBeanDefinitionReader  

348     if (this.parserClass != null) {   

349         XmlBeanDefinitionParser parser =   

350                 (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);   

351         return parser.registerBeanDefinitions(this, doc, resource);   

352     }   

353     // 具体的注册过程,首先得到XmlBeanDefinitionReader,来处理xmlbean定义文件  

354     BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();   

355     int countBefore = getBeanFactory().getBeanDefinitionCount();   

356     documentReader.registerBeanDefinitions(doc, createReaderContext(resource));   

357     return getBeanFactory().getBeanDefinitionCount() - countBefore;   

358 }  

359 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {  

360     // 这里定义解析器,使用XmlBeanDefinitionParser来解析xml方式的bean定义文件 现在的版本不用这个解析器了,使用的是XmlBeanDefinitionReader  

361     if (this.parserClass != null) {  

362         XmlBeanDefinitionParser parser =  

363                 (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);  

364         return parser.registerBeanDefinitions(this, doc, resource);  

365     }  

366     // 具体的注册过程,首先得到XmlBeanDefinitionReader,来处理xmlbean定义文件  

367     BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  

368     int countBefore = getBeanFactory().getBeanDefinitionCount();  

369     documentReader.registerBeanDefinitions(doc, createReaderContext(resource));  

370     return getBeanFactory().getBeanDefinitionCount() - countBefore;  

371 }  

具体的在BeanDefinitionDocumentReader中完成对,下面是一个简要的注册过程来完成bean定义文件的解析和IOC容器中bean的初始化
  

Java代码 

372 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {   

373     this.readerContext = readerContext;   

374   

375     logger.debug("Loading bean definitions");   

376     Element root = doc.getDocumentElement();   

377   

378     BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);   

379   

380     preProcessXml(root);   

381     parseBeanDefinitions(root, delegate);   

382     postProcessXml(root);   

383 }   

384   

385 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {   

386     if (delegate.isDefaultNamespace(root.getNamespaceURI())) {   

387         //这里得到xml文件的子节点,比如各个bean节点           

388         NodeList nl = root.getChildNodes();   

389   

390         //这里对每个节点进行分析处理  

391         for (int i = 0; i < nl.getLength(); i++) {   

392             Node node = nl.item(i);   

393             if (node instanceof Element) {   

394                 Element ele = (Element) node;   

395                 String namespaceUri = ele.getNamespaceURI();   

396                 if (delegate.isDefaultNamespace(namespaceUri)) {   

397                     //这里是解析过程的调用,对缺省的元素进行分析比如bean元素  

398                     parseDefaultElement(ele, delegate);   

399                 }   

400                 else {   

401                     delegate.parseCustomElement(ele);   

402                 }   

403             }   

404         }   

405     } else {   

406         delegate.parseCustomElement(root);   

407     }   

408 }   

409   

410 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {   

411     //这里对元素Import进行处理  

412     if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {   

413         importBeanDefinitionResource(ele);   

414     }   

415     else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {   

416         String name = ele.getAttribute(NAME_ATTRIBUTE);   

417         String alias = ele.getAttribute(ALIAS_ATTRIBUTE);   

418         getReaderContext().getReader().getBeanFactory().registerAlias(name, alias);   

419         getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));   

420     }   

421     //这里对我们最熟悉的bean元素进行处理  

422     else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {   

423         //委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包含了具体的bean解析的过程。  

424         // 把解析bean文件得到的信息放到BeanDefinition里,他是bean信息的主要载体,也是IOC容器的管理对象。  

425         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);   

426         if (bdHolder != null) {   

427             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);   

428             // 这里是向IOC容器注册,实际上是放到IOC容器的一个map  

429             BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());   

430   

431             // 这里向IOC容器发送事件,表示解析和注册完成。  

432             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));   

433         }   

434     }   

435 }  

436 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  

437     this.readerContext = readerContext;  

438   

439     logger.debug("Loading bean definitions");  

440     Element root = doc.getDocumentElement();  

441   

442     BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);  

443   

444     preProcessXml(root);  

445     parseBeanDefinitions(root, delegate);  

446     postProcessXml(root);  

447 }  

448   

449 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {  

450     if (delegate.isDefaultNamespace(root.getNamespaceURI())) {  

451         //这里得到xml文件的子节点,比如各个bean节点  

452         NodeList nl = root.getChildNodes();  

453   

454         //这里对每个节点进行分析处理  

455         for (int i = 0; i < nl.getLength(); i++) {  

456             Node node = nl.item(i);  

457             if (node instanceof Element) {  

458                 Element ele = (Element) node;  

459                 String namespaceUri = ele.getNamespaceURI();  

460                 if (delegate.isDefaultNamespace(namespaceUri)) {  

461                     //这里是解析过程的调用,对缺省的元素进行分析比如bean元素  

462                     parseDefaultElement(ele, delegate);  

463                 }  

464                 else {  

465                     delegate.parseCustomElement(ele);  

466                 }  

467             }  

468         }  

469     } else {  

470         delegate.parseCustomElement(root);  

471     }  

472 }  

473   

474 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  

475     //这里对元素Import进行处理  

476     if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {  

477         importBeanDefinitionResource(ele);  

478     }  

479     else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {  

480         String name = ele.getAttribute(NAME_ATTRIBUTE);  

481         String alias = ele.getAttribute(ALIAS_ATTRIBUTE);  

482         getReaderContext().getReader().getBeanFactory().registerAlias(name, alias);  

483         getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));  

484     }  

485     //这里对我们最熟悉的bean元素进行处理  

486     else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {  

487         //委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包含了具体的bean解析的过程。  

488         // 把解析bean文件得到的信息放到BeanDefinition里,他是bean信息的主要载体,也是IOC容器的管理对象。  

489         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  

490         if (bdHolder != null) {  

491             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  

492             // 这里是向IOC容器注册,实际上是放到IOC容器的一个map里  

493             BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  

494   

495             // 这里向IOC容器发送事件,表示解析和注册完成。  

496             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  

497         }  

498     }  

499 }  

我们看到在parseBeanDefinition中对具体bean元素的解析式交给BeanDefinitionParserDelegate来完成的,下面我们看看解析完的bean是怎样在IOC容器中注册的:
 在BeanDefinitionReaderUtils调用的是:
  

Java代码 

500 public static void registerBeanDefinition(   

501         BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory) throws BeansException {   

502   

503     // 这里得到需要注册bean的名字;  

504     String beanName = bdHolder.getBeanName();   

505     //这是调用IOC来注册的bean的过程,需要得到BeanDefinition  

506     beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition());   

507   

508     // 别名也是可以通过IOC容器和bean联系起来的进行注册  

509     String[] aliases = bdHolder.getAliases();   

510     if (aliases != null) {   

511         for (int i = 0; i < aliases.length; i++) {   

512             beanFactory.registerAlias(beanName, aliases[i]);   

513         }   

514     }   

515 }  

516 public static void registerBeanDefinition(  

517         BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory) throws BeansException {  

518   

519     // 这里得到需要注册bean的名字;  

520     String beanName = bdHolder.getBeanName();  

521     //这是调用IOC来注册的bean的过程,需要得到BeanDefinition  

522     beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition());  

523   

524     // 别名也是可以通过IOC容器和bean联系起来的进行注册  

525     String[] aliases = bdHolder.getAliases();  

526     if (aliases != null) {  

527         for (int i = 0; i < aliases.length; i++) {  

528             beanFactory.registerAlias(beanName, aliases[i]);  

529         }  

530     }  

531 }  

我们看看XmlBeanFactory中的注册实现:
  

Java代码 

532 //———————————————————————  

533 // 这里是IOC容器对BeanDefinitionRegistry接口的实现  

534 //———————————————————————  

535   

536 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)   

537         throws BeanDefinitionStoreException {   

538   

539     …..//这里省略了对BeanDefinition的验证过程  

540     //先看看在容器里是不是已经有了同名的bean,如果有抛出异常。  

541     Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);   

542     if (oldBeanDefinition != null) {   

543         if (!this.allowBeanDefinitionOverriding) {   

544         ………..   

545     }   

546     else {   

547         //bean的名字加到IOC容器中去  

548         this.beanDefinitionNames.add(beanName);   

549     }   

550     //这里把bean的名字和Bean定义联系起来放到一个HashMap中去,IOC容器通过这个Map来维护容器里的Bean定义信息。  

551     this.beanDefinitionMap.put(beanName, beanDefinition);   

552     removeSingleton(beanName);   

553 }  

554 //---------------------------------------------------------------------  

555 // 这里是IOC容器对BeanDefinitionRegistry接口的实现  

556 //---------------------------------------------------------------------  

557   

558 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  

559         throws BeanDefinitionStoreException {  

560   

561     .....//这里省略了对BeanDefinition的验证过程  

562     //先看看在容器里是不是已经有了同名的bean,如果有抛出异常。  

563     Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  

564     if (oldBeanDefinition != null) {  

565         if (!this.allowBeanDefinitionOverriding) {  

566         ...........  

567     }  

568     else {  

569         //bean的名字加到IOC容器中去  

570         this.beanDefinitionNames.add(beanName);  

571     }  

572     //这里把bean的名字和Bean定义联系起来放到一个HashMap中去,IOC容器通过这个Map来维护容器里的Bean定义信息。  

573     this.beanDefinitionMap.put(beanName, beanDefinition);  

574     removeSingleton(beanName);  

575 }  

这样就完成了Bean定义在IOC容器中的注册,就可被IOC容器进行管理和使用了。
 从上面的代码来看,我们总结一下IOC容器初始化的基本步骤:

    * 初始化的入口在容器实现中的refresh()调用来完成
     * bean 定义载入IOC容器使用的方法是loadBeanDefinition,其中的大致过程如下:通过ResourceLoader来完成资源文件位置的定 位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现,可以从类路径,文件系统, URL等方式来定为资源位置。如果是XmlBeanFactory作为IOC容器,那么需要为它指定bean定义的资源,也就是说bean定义文件时通过 抽象成Resource来被IOC容器处理的,容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的 是XmlBeanDefinitionReader来解析beanxml定义文件 – 实际的处理过程是委托给BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用 BeanDefinition对象来表示 – 这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition这些相关的方法 – 他们都是为处理BeanDefinitin服务的,IoC容器解析得到BeanDefinition以后,需要把它在IOC容器中注册,这由IOC实现 BeanDefinitionRegistry接口来实现。注册过程就是在IOC容器内部维护的一个HashMap来保存得到的 BeanDefinition的过程。这个HashMapIoC容器持有bean信息的场所,以后对bean的操作都是围绕这个HashMap来实现 的。
     * 然后我们就可以通过BeanFactoryApplicationContext来享受到Spring IOC的服务了.
 在使用IOC容器的时候,我们注意到除了少量粘合代码,绝大多数以正确IoC风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将把这些对象与容 器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。 Spring本身提供了对声明式载入web应用程序用法的应用程序上下文,并将其存储在ServletContext中的框架实现。具体可以参见以后的文 章。
 在使用Spring IOC容器的时候我们还需要区别两个概念:
 Beanfactory Factory bean,其中BeanFactory指的是IOC容器的编程抽象,比如ApplicationContext, XmlBeanFactory等,这些都是IOC容器的具体表现,需要使用什么样的容器由客户决定但Spring为我们提供了丰富的选择。而 FactoryBean只是一个可以在IOC容器中被管理的一个bean,是对各种处理过程和资源使用的抽象,Factory bean在需要时产生另一个对象,而不返回FactoryBean本省,我们可以把它看成是一个抽象工厂,对它的调用返回的是工厂生产的产品。所有的 Factory bean都实现特殊的org.springframework.beans.factory.FactoryBean接口,当使用容器中factory bean的时候,该容器不会返回factory bean本身,而是返回其生成的对象。Spring包括了大部分的通用资源和服务访问抽象的Factory bean的实现,其中包括:
 对JNDI查询的处理,对代理对象的处理,对事务性代理的处理,对RMI代理的处理等,这些我们都可以看成是具体的工厂,看成是SPRING为我们建立好 的工厂。也就是说Spring通过使用抽象工厂模式为我们准备了一系列工厂来生产一些特定的对象,免除我们手工重复的工作,我们要使用时只需要在IOC容 器里配置好就能很方便的使用了。
 现在我们来看看在Spring的事件机制,Spring中有3个标准事件,ContextRefreshEvent, ContextCloseEvent,RequestHandledEvent他们通过ApplicationEvent接口,同样的如果需要自定义时间 也只需要实现ApplicationEvent接口,参照ContextCloseEvent的实现可以定制自己的事件实现:
  

Java代码 

576 public class ContextClosedEvent extends ApplicationEvent {   

577   

578     public ContextClosedEvent(ApplicationContext source) {   

579         super(source);   

580     }   

581   

582     public ApplicationContext getApplicationContext() {   

583         return (ApplicationContext) getSource();   

584     }   

585 }  

586 public class ContextClosedEvent extends ApplicationEvent {  

587   

588     public ContextClosedEvent(ApplicationContext source) {  

589         super(source);  

590     }  

591   

592     public ApplicationContext getApplicationContext() {  

593         return (ApplicationContext) getSource();  

594     }  

595 }  

可以通过显现ApplicationEventPublishAware接口,将事件发布器耦合到ApplicationContext这样可以使用 ApplicationContext框架来传递和消费消息,然后在ApplicationContext中配置好bean就可以了,在消费消息的过程 中,接受者通过实现ApplicationListener接收消息。
 比如可以直接使用SpringScheduleTimerTaskTimerFactoryBean作为定时器定时产生消息,具体可以参见《Spring框架高级编程》。
 TimerFactoryBean是一个工厂bean,对其中的ScheduleTimerTask进行处理后输出,参考ScheduleTimerTask的实现发现它最后调用的是jreTimerTask
  

Java代码 

596 public void setRunnable(Runnable timerTask) {   

597     this.timerTask = new DelegatingTimerTask(timerTask);   

598 }  

599 public void setRunnable(Runnable timerTask) {  

600     this.timerTask = new DelegatingTimerTask(timerTask);  

601 }  

在书中给出了一个定时发送消息的例子,当然可以可以通过定时器作其他的动作,有两种方法:
 1.定义MethodInvokingTimerTaskFactoryBean定义要执行的特定bean的特定方法,对需要做什么进行封装定义;
 2.定义TimerTask类,通过extends TimerTask来得到,同时对需要做什么进行自定义
 然后需要定义具体的定时器参数,通过配置ScheduledTimerTask中的参数和timerTask来完成,以下是它需要定义的具体属性,timerTask是在前面已经定义好的bean
  

Java代码 

602 private TimerTask timerTask;   

603   

604 private long delay = 0;   

605   

606 private long period = 0;   

607   

608 private boolean fixedRate = false;  

609 private TimerTask timerTask;  

610   

611 private long delay = 0;  

612   

613 private long period = 0;  

614   

615 private boolean fixedRate = false;  

最后,需要在ApplicationContext中注册,需要把ScheduledTimerTask配置到FactoryBean – TimerFactoryBean,这样就由IOC容器来管理定时器了。参照
 TimerFactoryBean的属性,可以定制一组定时器。
  

Java代码 

616 public class TimerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {   

617   

618     protected final Log logger = LogFactory.getLog(getClass());   

619   

620     private ScheduledTimerTask[] scheduledTimerTasks;   

621   

622     private boolean daemon = false;   

623   

624     private Timer timer;   

625   

626     ………..   

627 }  

628 public class TimerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {  

629   

630     protected final Log logger = LogFactory.getLog(getClass());  

631   

632     private ScheduledTimerTask[] scheduledTimerTasks;  

633   

634     private boolean daemon = false;  

635   

636     private Timer timer;  

637   

638     ...........  

639 }  

如果要发送时间我们只需要在定义好的ScheduledTimerTaskspublish定义好的事件就可以了。具体可以参考书中例子的实现,这里只 是结合FactoryBean的原理做一些解释。如果结合事件和定时器机制,我们可以很方便的实现heartbeat(看门狗),书中给出了这个例子,这 个例子实际上结合了Spring事件和定时机制的使用两个方面的知识 – 当然了还有IOC容器的知识(任何Spring应用我想都逃不掉IOC的魔爪:)

上面我们分析了IOC容器本身的实现,下面我们看看在典型的web环境中,Spring IOC容器是怎样被载入和起作用的。
 简单的说,在web容器中,通过ServletContextSpringIOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需 要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理器等各种中间层对象。在这个上下文的基础上,和web MVC相关还会有一个上下文来保存控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。在web容器中启动Spring应用程序就是一个建立这 个上下文体系的过程。Springweb应用提供了上下文的扩展接口
 WebApplicationContext:
  

Java代码 

public interface WebApplicationContext extends ApplicationContext {   

    //这里定义的常量用于在ServletContext中存取根上下文  

    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";   

    ……   

    //WebApplicationContext来说,需要得到Web容器的ServletContext  

    ServletContext getServletContext();   

}  

public interface WebApplicationContext extends ApplicationContext {  

    //这里定义的常量用于在ServletContext中存取根上下文  

10     String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";  

11     ......  

12     //WebApplicationContext来说,需要得到Web容器的ServletContext  

13     ServletContext getServletContext();  

14 }  

而一般的启动过程,Spring会使用一个默认的实现,XmlWebApplicationContext – 这个上下文实现作为在web容器中的根上下文容器被建立起来,具体的建立过程在下面我们会详细分析。
  

Java代码 

15 public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {   

16   

17     /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/  

18     public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";   

19     public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";   

20     public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";   

21       

22     //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。  

23     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {   

24         //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析  

25         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);   

26   

27         beanDefinitionReader.setResourceLoader(this);   

28         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));   

29   

30         initBeanDefinitionReader(beanDefinitionReader);   

31         loadBeanDefinitions(beanDefinitionReader);   

32     }   

33   

34     protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {   

35     }   

36     //使用XmlBeanDefinitionReader来读入bean定义信息  

37     protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {   

38         String[] configLocations = getConfigLocations();   

39         if (configLocations != null) {   

40             for (int i = 0; i < configLocations.length; i++) {   

41                 reader.loadBeanDefinitions(configLocations[i]);   

42             }   

43         }   

44     }   

45     //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml  

46     protected String[] getDefaultConfigLocations() {   

47         if (getNamespace() != null) {   

48             return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};   

49         }   

50         else {   

51             return new String[] {DEFAULT_CONFIG_LOCATION};   

52         }   

53     }   

54 }  

55 public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {  

56   

57     /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/  

58     public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";  

59     public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";  

60     public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";  

61   

62     //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。  

63     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {  

64         //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析  

65         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  

66   

67         beanDefinitionReader.setResourceLoader(this);  

68         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  

69   

70         initBeanDefinitionReader(beanDefinitionReader);  

71         loadBeanDefinitions(beanDefinitionReader);  

72     }  

73   

74     protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {  

75     }  

76     //使用XmlBeanDefinitionReader来读入bean定义信息  

77     protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  

78         String[] configLocations = getConfigLocations();  

79         if (configLocations != null) {  

80             for (int i = 0; i < configLocations.length; i++) {  

81                 reader.loadBeanDefinitions(configLocations[i]);  

82             }  

83         }  

84     }  

85     //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml  

86     protected String[] getDefaultConfigLocations() {  

87         if (getNamespace() != null) {  

88             return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};  

89         }  

90         else {  

91             return new String[] {DEFAULT_CONFIG_LOCATION};  

92         }  

93     }  

94 }  

对于一个Spring激活的web应用程序,可以通过使用Spring代码声明式的指定在web应用程序启动时载入应用程序上下文 (WebApplicationContext),SpringContextLoader是提供这样性能的类,我们可以使用 ContextLoaderServlet或者ContextLoaderListener的启动时载入的Servlet来实例化Spring IOC容器 – 为什么会有两个不同的类来装载它呢,这是因为它们的使用需要区别不同的Servlet容器支持的Serlvet版本。但不管是 ContextLoaderSevlet还是 ContextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这 个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些Servlet的具体使用我们都要借助web容器中的部署描述符来进行相关的定义。
 下面我们使用ContextLoaderListener作为载入器作一个详细的分析,这个Servlet的监听器是根上下文被载入的地方,也是整个 Spring web应用加载上下文的第一个地方;从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然后可以读到 配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根 上下文。当这个根上下文被载入后,它被绑定到web应用程序的ServletContext上。任何需要访问该ApplicationContext的应 用程序代码都可以从WebApplicationContextUtils类的静态方法来得到:
  

Java代码 

95 WebApplicationContext getWebApplicationContext(ServletContext sc)  

96 WebApplicationContext getWebApplicationContext(ServletContext sc)  

Tomcat作为Servlet容器为例,下面是具体的步骤:
 1.Tomcat 启动时需要从web.xml中读取启动参数,在web.xml中我们需要对ContextLoaderListener进行配置,对于在web应用启动入 口是在ContextLoaderListener中的初始化部分;从Spring MVC上看,实际上在web容器中维护了一系列的IOC容器,其中在ContextLoader中载入的IOC容器作为根上下文而存在于 ServletContext中。
  

Java代码 

97 //这里对根上下文进行初始化。  

98 public void contextInitialized(ServletContextEvent event) {   

99     //这里创建需要的ContextLoader  

100     this.contextLoader = createContextLoader();   

101     //这里使用ContextLoader对根上下文进行载入和初始化  

102     this.contextLoader.initWebApplicationContext(event.getServletContext());   

103 }  

104 //这里对根上下文进行初始化。  

105 public void contextInitialized(ServletContextEvent event) {  

106     //这里创建需要的ContextLoader  

107     this.contextLoader = createContextLoader();  

108     //这里使用ContextLoader对根上下文进行载入和初始化  

109     this.contextLoader.initWebApplicationContext(event.getServletContext());  

110 }  

通过ContextLoader建立起根上下文的过程,我们可以在ContextLoader中看到:
  

Java代码 

111 public WebApplicationContext initWebApplicationContext(ServletContext servletContext)   

112         throws IllegalStateException, BeansException {   

113     //这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有错误。  

114     if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {   

115     //直接抛出异常  

116     ………   

117     }   

118      

119     ……………   

120     try {   

121         // 这里载入根上下文的父上下文  

122         ApplicationContext parent = loadParentContext(servletContext);   

123   

124         //这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的ServletContext的属性值是  

125         //ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据这个属性值来取得根上下文的 往往作为自己上下文的父上下文  

126         this.context = createWebApplicationContext(servletContext, parent);   

127         servletContext.setAttribute(   

128                 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);   

129         ……….   

130   

131         return this.context;   

132     }   

133        …………   

134 }  

135 public WebApplicationContext initWebApplicationContext(ServletContext servletContext)  

136         throws IllegalStateException, BeansException {  

137     //这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有错误。  

138     if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {  

139     //直接抛出异常  

140     .........  

141     }  

142   

143     ...............  

144     try {  

145         // 这里载入根上下文的父上下文  

146         ApplicationContext parent = loadParentContext(servletContext);  

147   

148         //这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的ServletContext的属性值是  

149         //ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据这个属性值来取得根上下文的 往往作为自己上下文的父上下文  

150         this.context = createWebApplicationContext(servletContext, parent);  

151         servletContext.setAttribute(  

152                 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);  

153         ..........  

154   

155         return this.context;  

156     }  

157        ............  

158 }  

建立根上下文的父上下文使用的是下面的代码,取决于在web.xml中定义的参数:locatorFactorySelector,这是一个可选参数:
  

Java代码 

159 protected ApplicationContext loadParentContext(ServletContext servletContext)   

160         throws BeansException {   

161   

162     ApplicationContext parentContext = null;   

163   

164     String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);   

165     String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);   

166   

167     if (locatorFactorySelector != null) {   

168         BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);   

169         ……..   

170         //得到根上下文的父上下文的引用  

171         this.parentContextRef = locator.useBeanFactory(parentContextKey);   

172         //这里建立得到根上下文的父上下文  

173         parentContext = (ApplicationContext) this.parentContextRef.getFactory();   

174     }   

175   

176     return parentContext;   

177 }  

178 protected ApplicationContext loadParentContext(ServletContext servletContext)  

179         throws BeansException {  

180   

181     ApplicationContext parentContext = null;  

182   

183     String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);  

184     String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);  

185   

186     if (locatorFactorySelector != null) {  

187         BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);  

188         ........  

189         //得到根上下文的父上下文的引用  

190         this.parentContextRef = <a href="http://locator.us" title="http://locator.us" target="_blank">locator.us</a>eBeanFactory(parentContextKey);  

191         //这里建立得到根上下文的父上下文  

192         parentContext = (ApplicationContext) this.parentContextRef.getFactory();  

193     }  

194   

195     return parentContext;  

196 }  

得到根上下文的父上下文以后,就是根上下文的创建过程:
  

Java代码 

197 protected WebApplicationContext createWebApplicationContext(   

198         ServletContext servletContext, ApplicationContext parent) throws BeansException {   

199     //这里需要确定我们载入的根WebApplication的类型,由在web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext,  

200     //如果没有使用默认的。  

201     Class contextClass = determineContextClass(servletContext);   

202     ………   

203     //这里就是上下文的创建过程  

204     ConfigurableWebApplicationContext wac =   

205             (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);   

206     //这里保持对父上下文和ServletContext的引用到根上下文中  

207     wac.setParent(parent);   

208     wac.setServletContext(servletContext);   

209   

210     //这里从web.xml中取得相关的初始化参数  

211     String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);   

212     if (configLocation != null) {   

213         wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,   

214                 ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));   

215     }   

216    //这里对WebApplicationContext进行初始化,我们又看到了熟悉的refresh调用。  

217     wac.refresh();   

218     return wac;   

219 }  

220 protected WebApplicationContext createWebApplicationContext(  

221         ServletContext servletContext, ApplicationContext parent) throws BeansException {  

222     //这里需要确定我们载入的根WebApplication的类型,由在web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext,  

223     //如果没有使用默认的。  

224     Class contextClass = determineContextClass(servletContext);  

225     .........  

226     //这里就是上下文的创建过程  

227     ConfigurableWebApplicationContext wac =  

228             (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);  

229     //这里保持对父上下文和ServletContext的引用到根上下文中  

230     wac.setParent(parent);  

231     wac.setServletContext(servletContext);  

232   

233     //这里从web.xml中取得相关的初始化参数  

234     String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);  

235     if (configLocation != null) {  

236         wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,  

237                 ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));  

238     }  

239    //这里对WebApplicationContext进行初始化,我们又看到了熟悉的refresh调用。  

240     wac.refresh();  

241     return wac;  

242 }  

初始化根ApplicationContext后将其存储到SevletContext中去以后,这样就建立了一个全局的关于整个应用的上下文。这个根上 下文会被以后的DispatcherServlet初始化自己的时候作为自己ApplicationContext的父上下文。这个在对 DispatcherServlet做分析的时候我们可以看看到。

3.完成对ContextLoaderListener的初始化以后, Tomcat开始初始化DispatchServlet还记得我们在web.xml中队载入次序进行了定义。DispatcherServlet会建立自己的ApplicationContext,同时建立这 个自己的上下文的时候会从ServletContext中得到根上下文作为父上下文,然后再对自己的上下文进行初始化,并最后存到 ServletContext中去供以后检索和使用。
 可以从DispatchServlet的父类FrameworkServlet的代码中看到大致的初始化过程,整个ApplicationContext的创建过程和ContextLoder创建的过程相类似:
  

Java代码 

243 protected final void initServletBean() throws ServletException, BeansException {   

244     ………   

245     try {   

246         //这里是对上下文的初始化过程。  

247         this.webApplicationContext = initWebApplicationContext();   

248         //在完成对上下文的初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素  

249         initFrameworkServlet();   

250     }   

251    ……..   

252 }  

253 protected final void initServletBean() throws ServletException, BeansException {  

254     .........  

255     try {  

256         //这里是对上下文的初始化过程。  

257         this.webApplicationContext = initWebApplicationContext();  

258         //在完成对上下文的初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素  

259         initFrameworkServlet();  

260     }  

261    ........  

262 }  

initWebApplicationContext()调用的代码如下:
  

Java代码 

263 protected WebApplicationContext initWebApplicationContext() throws BeansException {   

264     //这里调用WebApplicationContextUtils静态类来得到根上下文  

265     WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());   

266       

267     //创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;  

268     WebApplicationContext wac = createWebApplicationContext(parent);   

269     ……..   

270     if (isPublishContext()) {   

271         //把当前建立的上下文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。  

272         String attrName = getServletContextAttributeName();   

273         getServletContext().setAttribute(attrName, wac);   

274     }   

275     return wac;   

276 }  

277 protected WebApplicationContext initWebApplicationContext() throws BeansException {  

278     //这里调用WebApplicationContextUtils静态类来得到根上下文  

279     WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());  

280   

281     //创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;  

282     WebApplicationContext wac = createWebApplicationContext(parent);  

283     ........  

284     if (isPublishContext()) {  

285         //把当前建立的上下文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。  

286         String attrName = getServletContextAttributeName();  

287         getServletContext().setAttribute(attrName, wac);  

288     }  

289     return wac;  

290 }  

其中我们看到调用了WebApplicationContextUtils的静态方法得到根ApplicationContext:
  

Java代码 

291     public static WebApplicationContext getWebApplicationContext(ServletContext sc) {   

292         //很简单,直接从ServletContext中通过属性名得到根上下文  

293         Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);   

294         …….   

295         return (WebApplicationContext) attr;   

296     }   

297 然后创建DispatcherServlet自己的WebApplicationContext:   

298     protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)   

299             throws BeansException {   

300         …….   

301         //这里使用了BeanUtils直接得到WebApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS =                             

302         //XmlWebApplicationContext.class;  

303         ConfigurableWebApplicationContext wac =   

304                 (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());   

305   

306         //这里配置父上下文,就是在ContextLoader中建立的根上下文  

307         wac.setParent(parent);   

308   

309         //保留ServletContext的引用和相关的配置信息。  

310         wac.setServletContext(getServletContext());   

311         wac.setServletConfig(getServletConfig());   

312         wac.setNamespace(getNamespace());   

313   

314         //这里得到ApplicationContext配置文件的位置  

315         if (getContextConfigLocation() != null) {   

316             wac.setConfigLocations(   

317                 StringUtils.tokenizeToStringArray(   

318                             getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));   

319         }   

320           

321         //这里调用ApplicationContext的初始化过程,同样需要使用refresh()  

322         wac.refresh();   

323         return wac;   

324     }  

325     public static WebApplicationContext getWebApplicationContext(ServletContext sc) {  

326         //很简单,直接从ServletContext中通过属性名得到根上下文  

327         Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);  

328         .......  

329         return (WebApplicationContext) attr;  

330     }  

331 然后创建DispatcherServlet自己的WebApplicationContext:  

332     protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)  

333             throws BeansException {  

334         .......  

335         //这里使用了BeanUtils直接得到WebApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS =  

336         //XmlWebApplicationContext.class;  

337         ConfigurableWebApplicationContext wac =  

338                 (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());  

339   

340         //这里配置父上下文,就是在ContextLoader中建立的根上下文  

341         wac.setParent(parent);  

342   

343         //保留ServletContext的引用和相关的配置信息。  

344         wac.setServletContext(getServletContext());  

345         wac.setServletConfig(getServletConfig());  

346         wac.setNamespace(getNamespace());  

347   

348         //这里得到ApplicationContext配置文件的位置  

349         if (getContextConfigLocation() != null) {  

350             wac.setConfigLocations(  

351                 StringUtils.tokenizeToStringArray(  

352                             getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));  

353         }  

354   

355         //这里调用ApplicationContext的初始化过程,同样需要使用refresh()  

356         wac.refresh();  

357         return wac;  

358     }  

4. 然后就是DispatchServlet中对Spring MVC的配置过程,首先对配置文件中的定义元素进行配置 – 请注意这个时候我们的WebApplicationContext已经建立起来了,也意味着DispatcherServlet有自己的定义资源,可以需 要从web.xml中读取bean的配置信息,通常我们会使用单独的xml文件来配置MVC中各个要素定义,这里和web容器相关的加载过程实际上已经完 成了,下面的处理和普通的Spring应用程序的编写没有什么太大的差别,我们先看看MVC的初始化过程:
  

Java代码 

359 protected void initFrameworkServlet() throws ServletException, BeansException {   

360     initMultipartResolver();   

361     initLocaleResolver();   

362     initThemeResolver();   

363     initHandlerMappings();   

364     initHandlerAdapters();   

365     initHandlerExceptionResolvers();   

366     initRequestToViewNameTranslator();   

367     initViewResolvers();   

368 }  

369 protected void initFrameworkServlet() throws ServletException, BeansException {  

370     initMultipartResolver();  

371     initLocaleResolver();  

372     initThemeResolver();  

373     initHandlerMappings();  

374     initHandlerAdapters();  

375     initHandlerExceptionResolvers();  

376     initRequestToViewNameTranslator();  

377     initViewResolvers();  

378 }  

5. 这样MVC的框架就建立起来了,DispatchServlet对接受到的HTTP Request进行分发处理由doService()完成,具体的MVC处理过程我们在doDispatch()中完成,其中包括使用Command模式 建立执行链,显示模型数据等,这些处理我们都可以在DispatcherServlet的代码中看到:
  

Java代码 

379 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {   

380     ……   

381     try {   

382         doDispatch(request, response);   

383     }   

384    …….   

385 }  

386 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  

387     ......  

388     try {  

389         doDispatch(request, response);  

390     }  

391    .......  

392 }  

实际的请求分发由doDispatch(request,response)来完成:
  

Java代码 

393 protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception {   

394      …….   

395      // 这是Spring定义的执行链,里面放了映射关系对应的handler和定义的相关拦截器。  

396      HandlerExecutionChain mappedHandler = null;   

397       

398       ……   

399       try {   

400           //我们熟悉的ModelAndView在这里出现了。  

401           ModelAndView mv = null;   

402           try {   

403               processedRequest = checkMultipart(request);   

404   

405               //这里更具request中的参数和映射关系定义决定使用的handler  

406               mappedHandler = getHandler(processedRequest, false);   

407   

408               ……   

409               //这里是handler的调用过程,类似于Command模式中的execute.  

410               HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());   

411               mv = ha.handle(processedRequest, response, mappedHandler.getHandler());   

412   

413               …….   

414           //这里将模型数据通过视图进行展现  

415           if (mv != null && !mv.wasCleared()) {   

416               render(mv, processedRequest, response);   

417           }   

418             ……..   

419   }  

420 protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception {  

421      .......  

422      // 这是Spring定义的执行链,里面放了映射关系对应的handler和定义的相关拦截器。  

423      HandlerExecutionChain mappedHandler = null;  

424   

425       ......  

426       try {  

427           //我们熟悉的ModelAndView在这里出现了。  

428           ModelAndView mv = null;  

429           try {  

430               processedRequest = checkMultipart(request);  

431   

432               //这里更具request中的参数和映射关系定义决定使用的handler  

433               mappedHandler = getHandler(processedRequest, false);  

434   

435               ......  

436               //这里是handler的调用过程,类似于Command模式中的execute.  

437               HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  

438               mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

439   

440               .......  

441           //这里将模型数据通过视图进行展现  

442           if (mv != null && !mv.wasCleared()) {  

443               render(mv, processedRequest, response);  

444           }  

445             ........  

446   }  

这样具体的MVC模型的实现就由bean配置文件里定义好的view resolver,handler这些类来实现用户代码的功能。
 总结上面的过程,我们看到在web容器中,ServletContext可以持有一系列的web上下文,而在整个web上下文中存在一个根上下文来作为其 它 Servlet上下文的父上下文。这个根上下文是由ContextLoader载入并进行初始化的,对于我们的web应用, DispatcherSerlvet载入并初始化自己的上下文,这个上下文的父上下文是根上下文,并且我们也能从ServletContext中根据 Servlet的名字来检索到我们需要的对应于这个Servlet的上下文,但是根上下文的名字是由Spring唯一确定的。这个 DispactcherServlet建立的上下文就是我们开发Spring MVC应用的IOC容器。
 具体的web请求处理在上下文体系建立完成以后由DispactcherServlet来完成,上面对MVC的运作做了一个大致的描述,下面我们会具体就SpringMVC的框架实现作一个详细的分析。

Spring中,JdbcTemplate是经常被使用的类来帮助用户程序操作数据库,在JdbcTemplate为用户程序提供了许多便利的数 据库操作方法,比如查询,更新等,而且在Spring中,有许多类似 JdbcTemplate的模板,比如HibernateTemplate等等 – 看来这是Rod.Johnson的惯用手法,一般而言这种Template中都是通过回调函数CallBack类的使用来完成功能的,客户需要在回调接口 中实现自己需要的定制行为,比如使用客户想要用的SQL语句等。不过往往Spring通过这种回调函数的实现已经为我们提供了许多现成的方法供客户使用。 一般来说回调函数的用法采用匿名类的方式来实现,比如:
  

Java代码 

JdbcTemplate = new JdbcTemplate(datasource);   

jdbcTemplate.execute(new CallBack(){   

            public CallbackInterfacedoInAction(){   

               ……   

               //用户定义的代码或者说Spring替我们实现的代码  

            }   

}  

JdbcTemplate = new JdbcTemplate(datasource);  

jdbcTemplate.execute(new CallBack(){  

10             public CallbackInterfacedoInAction(){  

11                ......  

12                //用户定义的代码或者说Spring替我们实现的代码  

13             }  

14 }  

在模板中嵌入的是需要客户化的代码,由Spring来作或者需要客户程序亲自动手完成。下面让我们具体看看在JdbcTemplate中的代码是怎样完成 使命的,我们举JdbcTemplate.execute()为例,这个方法是在JdbcTemplate中被其他方法调用的基本方法之一,客户程序往往 用这个方法来执行基本的SQL语句:
  

Java代码 

15 public Object execute(ConnectionCallback action) throws DataAccessException {   

16     //这里得到数据库联接  

17     Connection con = DataSourceUtils.getConnection(getDataSource());   

18     try {   

19         Connection conToUse = con;   

20         //有些特殊的数据库,需要我们使用特别的方法取得datasource  

21         if (this.nativeJdbcExtractor != null) {   

22             // Extract native JDBC Connection, castable to OracleConnection or the like.  

23             conToUse = this.nativeJdbcExtractor.getNativeConnection(con);   

24         }   

25         else {   

26             // Create close-suppressing Connection proxy, also preparing returned Statements.  

27             conToUse = createConnectionProxy(con);   

28         }   

29     //这里调用的是传递进来的匿名类的方法,也就是用户程序需要实现CallBack接口的地方。  

30         return action.doInConnection(conToUse);   

31     }   

32     catch (SQLException ex) {   

33         //如果捕捉到数据库异常,把数据库联接释放,同时抛出一个经过Spring转换过的Spring数据库异常,  

34         //我们知道,Spring做了一个有意义的工作是把这些数据库异常统一到自己的异常体系里了。  

35         DataSourceUtils.releaseConnection(con, getDataSource());   

36         con = null;   

37         throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);   

38     }   

39     finally {   

40         //最后不管怎样都会把数据库连接释放  

41         DataSourceUtils.releaseConnection(con, getDataSource());   

42     }   

43 }  

44 public Object execute(ConnectionCallback action) throws DataAccessException {  

45     //这里得到数据库联接  

46     Connection con = DataSourceUtils.getConnection(getDataSource());  

47     try {  

48         Connection conToUse = con;  

49         //有些特殊的数据库,需要我们使用特别的方法取得datasource  

50         if (this.nativeJdbcExtractor != null) {  

51             // Extract native JDBC Connection, castable to OracleConnection or the like.  

52             conToUse = this.nativeJdbcExtractor.getNativeConnection(con);  

53         }  

54         else {  

55             // Create close-suppressing Connection proxy, also preparing returned Statements.  

56             conToUse = createConnectionProxy(con);  

57         }  

58     //这里调用的是传递进来的匿名类的方法,也就是用户程序需要实现CallBack接口的地方。  

59         return action.doInConnection(conToUse);  

60     }  

61     catch (SQLException ex) {  

62         //如果捕捉到数据库异常,把数据库联接释放,同时抛出一个经过Spring转换过的Spring数据库异常,  

63         //我们知道,Spring做了一个有意义的工作是把这些数据库异常统一到自己的异常体系里了。  

64         DataSourceUtils.releaseConnection(con, getDataSource());  

65         con = null;  

66         throw getExceptionTranslator().translate("ConnectionCallback", getSql(action), ex);  

67     }  

68     finally {  

69         //最后不管怎样都会把数据库连接释放  

70         DataSourceUtils.releaseConnection(con, getDataSource());  

71     }  

72 }  

对于JdbcTemplate中给出的其他方法,比如query,update,execute等的实现,我们看看query()
  

Java代码 

73 public Object query(PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)   

74         throws DataAccessException {   

75     ……….   

76     //这里调用了我们上面看到的execute()基本方法,然而这里的回调实现是Spring为我们完成的查询过程  

77     return execute(psc, new PreparedStatementCallback() {   

78         public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {   

79             //准备查询结果集  

80             ResultSet rs = null;   

81             try {   

82             //这里配置SQL参数  

83                 if (pss != null) {   

84                     pss.setValues(ps);   

85                 }   

86           //这里执行的SQL查询  

87                 rs = ps.executeQuery();   

88                 ResultSet rsToUse = rs;   

89                 if (nativeJdbcExtractor != null) {   

90                     rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);   

91                 }   

92          //返回需要的记录集合  

93                 return rse.extractData(rsToUse);   

94             }   

95             finally {   

96         //最后关闭查询的纪录集,对数据库连接的释放在execute()中释放,就像我们在上面分析的看到那样。  

97                 JdbcUtils.closeResultSet(rs);   

98                 if (pss instanceof ParameterDisposer) {   

99                     ((ParameterDisposer) pss).cleanupParameters();   

100                 }   

101             }   

102         }   

103     });   

104 }  

105 public Object query(PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)  

106         throws DataAccessException {  

107     ..........  

108     //这里调用了我们上面看到的execute()基本方法,然而这里的回调实现是Spring为我们完成的查询过程  

109     return execute(psc, new PreparedStatementCallback() {  

110         public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {  

111             //准备查询结果集  

112             ResultSet rs = null;  

113             try {  

114             //这里配置SQL参数  

115                 if (pss != null) {  

116                     pss.setValues(ps);  

117                 }  

118           //这里执行的SQL查询  

119                 rs = ps.executeQuery();  

120                 ResultSet rsToUse = rs;  

121                 if (nativeJdbcExtractor != null) {  

122                     rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);  

123                 }  

124          //返回需要的记录集合  

125                 return rse.extractData(rsToUse);  

126             }  

127             finally {  

128         //最后关闭查询的纪录集,对数据库连接的释放在execute()中释放,就像我们在上面分析的看到那样。  

129                 JdbcUtils.closeResultSet(rs);  

130                 if (pss instanceof ParameterDisposer) {  

131                     ((ParameterDisposer) pss).cleanupParameters();  

132                 }  

133             }  

134         }  

135     });  

136 }  

辅助类DataSourceUtils来用来对数据库连接进行管理的主要工具,比如打开和关闭数据库连接等基本操作:
  

Java代码 

137 public static Connection doGetConnection(DataSource dataSource) throws SQLException {   

138    //把对数据库连接放到事务管理里面进行管理  

139     ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);   

140     if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {   

141         conHolder.requested();   

142         if (!conHolder.hasConnection()) {   

143             logger.debug("Fetching resumed JDBC Connection from DataSource");   

144             conHolder.setConnection(dataSource.getConnection());   

145         }   

146         return conHolder.getConnection();   

147     }   

148     // 这里得到需要的数据库连接,在配置文件中定义好的。  

149     logger.debug("Fetching JDBC Connection from DataSource");   

150     Connection con = dataSource.getConnection();   

151   

152     if (TransactionSynchronizationManager.isSynchronizationActive()) {   

153         logger.debug("Registering transaction synchronization for JDBC Connection");   

154         // Use same Connection for further JDBC actions within the transaction.  

155         // Thread-bound object will get removed by synchronization at transaction completion.  

156         ConnectionHolder holderToUse = conHolder;   

157         if (holderToUse == null) {   

158             holderToUse = new ConnectionHolder(con);   

159         }   

160         else {   

161             holderToUse.setConnection(con);   

162         }   

163         holderToUse.requested();   

164         TransactionSynchronizationManager.registerSynchronization(   

165                 new ConnectionSynchronization(holderToUse, dataSource));   

166         holderToUse.setSynchronizedWithTransaction(true);   

167         if (holderToUse != conHolder) {   

168             TransactionSynchronizationManager.bindResource(dataSource, holderToUse);   

169         }   

170     }   

171   

172     return con;   

173 }  

174 public static Connection doGetConnection(DataSource dataSource) throws SQLException {  

175    //把对数据库连接放到事务管理里面进行管理  

176     ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);  

177     if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {  

178         conHolder.requested();  

179         if (!conHolder.hasConnection()) {  

180             logger.debug("Fetching resumed JDBC Connection from DataSource");  

181             conHolder.setConnection(dataSource.getConnection());  

182         }  

183         return conHolder.getConnection();  

184     }  

185     // 这里得到需要的数据库连接,在配置文件中定义好的。  

186     logger.debug("Fetching JDBC Connection from DataSource");  

187     Connection con = dataSource.getConnection();  

188   

189     if (TransactionSynchronizationManager.isSynchronizationActive()) {  

190         logger.debug("Registering transaction synchronization for JDBC Connection");  

191         // Use same Connection for further JDBC actions within the transaction.  

192         // Thread-bound object will get removed by synchronization at transaction completion.  

193         ConnectionHolder holderToUse = conHolder;  

194         if (holderToUse == null) {  

195             holderToUse = new ConnectionHolder(con);  

196         }  

197         else {  

198             holderToUse.setConnection(con);  

199         }  

200         holderToUse.requested();  

201         TransactionSynchronizationManager.registerSynchronization(  

202                 new ConnectionSynchronization(holderToUse, dataSource));  

203         holderToUse.setSynchronizedWithTransaction(true);  

204         if (holderToUse != conHolder) {  

205             TransactionSynchronizationManager.bindResource(dataSource, holderToUse);  

206         }  

207     }  

208   

209     return con;  

210 }  

那我们实际的DataSource对象是怎样得到的?很清楚我们需要在上下文中进行配置:它作为JdbcTemplate父类JdbcAccessor的属性存在:
  

Java代码 

211 public abstract class JdbcAccessor implements InitializingBean {   

212   

213     /** 这里是我们依赖注入数据库数据源的地方。 */  

214     private DataSource dataSource;   

215   

216     /** Helper to translate SQL exceptions to DataAccessExceptions */  

217     private SQLExceptionTranslator exceptionTranslator;   

218   

219     private boolean lazyInit = true;   

220   

221     ……..   

222 }  

223 public abstract class JdbcAccessor implements InitializingBean {  

224   

225     /** 这里是我们依赖注入数据库数据源的地方。 */  

226     private DataSource dataSource;  

227   

228     /** Helper to translate SQL exceptions to DataAccessExceptions */  

229     private SQLExceptionTranslator exceptionTranslator;  

230   

231     private boolean lazyInit = true;  

232   

233     ........  

234 }  

而对于DataSource的缓冲池实现,我们通过定义Apache Jakarta Commons DBCP或者C3P0提供的DataSource来完成,然后只要在上下文中配置好就可以使用了。从上面我们看到JdbcTemplate提供了许多简单 查询和更新功能,但是如果需要更高层次的抽象,以及更面向对象的方法来访问数据库。Spring为我们提供了 org.springframework.jdbc.object包,这里面包含了SqlQuery,SqlMappingQuery, SqlUpdateStoredProcedure等类,这些类都是Spring JDBC应用程序可以使用的主要类,但我们要注意使用这些类的时候,用户需要为他们配置好一个JdbcTemplate作为其基本的操作的实现。
 比如说我们使用MappingSqlQuery来将表数据直接映射到一个对象集合 – 具体可以参考书中的例子
 1.我们需要建立DataSourcesql语句并建立持有这些对象的MappingSqlQuery对象
 2.然后我们需要定义传递的SqlParameter,具体的实现我们在MappingSqlQuery的父类RdbmsOperation中可以找到:
  

Java代码 

235 public void declareParameter(SqlParameter param) throws InvalidDataAccessApiUsageException {   

236    //如果声明已经被编译过,则该声明无效  

237    if (isCompiled()) {   

238        throw new InvalidDataAccessApiUsageException("Cannot add parameters once query is compiled");   

239    }   

240    //这里对参数值进行声明定义  

241    this.declaredParameters.add(param);   

242 public void declareParameter(SqlParameter param) throws InvalidDataAccessApiUsageException {  

243    //如果声明已经被编译过,则该声明无效  

244    if (isCompiled()) {  

245        throw new InvalidDataAccessApiUsageException("Cannot add parameters once query is compiled");  

246    }  

247    //这里对参数值进行声明定义  

248    this.declaredParameters.add(param);  

而这个declareParameters维护的是一个列表:
  

Java代码 

249 /** List of SqlParameter objects */  

250 private List declaredParameters = new LinkedList();  

251 /** List of SqlParameter objects */  

252 private List declaredParameters = new LinkedList();  

这个列表在以后compile的过程中会被使用。
 3.然后用户程序需要实现MappingSqlQuerymapRow接口,将具体的ResultSet数据生成我们需要的对象,这是我们迭代使用的方法。123步实际上为我们定义好了一个迭代的基本单元作为操作模板。
 4.在应用程序,我们直接调用execute()方法得到我们需要的对象列表,列表中的每一个对象的数据来自于执行SQL语句得到记录集的每一条记录,事实上执行的execute在父类SqlQuery中起作用:
  

Java代码 

253 public List executeByNamedParam(Map paramMap, Map context) throws DataAccessException {   

254     validateNamedParameters(paramMap);   

255     Object[] parameters = NamedParameterUtils.buildValueArray(getSql(), paramMap);   

256     RowMapper rowMapper = newRowMapper(parameters, context);   

257     String sqlToUse = NamedParameterUtils.substituteNamedParameters(getSql(), new MapSqlParameterSource(paramMap));   

258     //我们又看到了JdbcTemplate,这里使用JdbcTemplate来完成对数据库的查询操作,所以我们说JdbcTemplate是基本的操作类。  

259      return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, parameters), rowMapper);   

260 }  

261 public List executeByNamedParam(Map paramMap, Map context) throws DataAccessException {  

262     validateNamedParameters(paramMap);  

263     Object[] parameters = NamedParameterUtils.buildValueArray(getSql(), paramMap);  

264     RowMapper rowMapper = newRowMapper(parameters, context);  

265     String sqlToUse = NamedParameterUtils.substituteNamedParameters(getSql(), new MapSqlParameterSource(paramMap));  

266     //我们又看到了JdbcTemplate,这里使用JdbcTemplate来完成对数据库的查询操作,所以我们说JdbcTemplate是基本的操作类。  

267      return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, parameters), rowMapper);  

268 }  

在这里我们可以看到template模式的精彩应用和对JdbcTemplate的灵活使用。通过使用它,我们免去了手工迭代ResultSet并将其中 的数据转化为对象列表的重复过程。在这里我们只需要定义SQL语句和SqlParameter – 如果需要的话,往往SQL语句就常常能够满足我们的要求了。这是灵活使用JdbcTemplate的一个很好的例子。
 Spring还为其他数据库操作提供了许多服务,比如使用SqlUpdate插入和更新数据库,使用UpdatableSqlQuery更新ResultSet,生成主键,调用存储过程等。
 书中还给出了对BLOB数据和CLOB数据进行数据库操作的例子:
 对BLOB数据的操作通过LobHander来完成,通过调用JdbcTemplateRDBMS都可以进行操作:
 在JdbcTemplate中,具体的调用可以参考书中的例子 – 是通过以下调用起作用的:
  

Java代码 

269 public Object execute(String sql, PreparedStatementCallback action) throws DataAccessException {   

270     return execute(new SimplePreparedStatementCreator(sql), action);   

271 }  

272 public Object execute(String sql, PreparedStatementCallback action) throws DataAccessException {  

273     return execute(new SimplePreparedStatementCreator(sql), action);  

274 }  

然后通过对实现PreparedStatementCallback接口的AbstractLobCreatingPreparedStatementCallback的回调函数来完成:
  

Java代码 

275 public final Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {   

276     LobCreator lobCreator = this.lobHandler.getLobCreator();   

277     try {   

278         //这是一个模板方法,具体需要由客户程序实现  

279         setValues(ps, lobCreator);   

280         return new Integer(ps.executeUpdate());   

281     }   

282     finally {   

283         lobCreator.close();   

284     }   

285 }   

286 //定义的需要客户程序实现的虚函数  

287 protected abstract void setValues(PreparedStatement ps, LobCreator lobCreator)   

288         throws SQLException, DataAccessException;  

289 public final Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {  

290     LobCreator lobCreator = this.lobHandler.getLobCreator();  

291     try {  

292         //这是一个模板方法,具体需要由客户程序实现  

293         setValues(ps, lobCreator);  

294         return new Integer(ps.executeUpdate());  

295     }  

296     finally {  

297         lobCreator.close();  

298     }  

299 }  

300 //定义的需要客户程序实现的虚函数  

301 protected abstract void setValues(PreparedStatement ps, LobCreator lobCreator)  

302         throws SQLException, DataAccessException;  

而我们注意到setValues()是一个需要实现的抽象方法,应用程序通过实现setValues来定义自己的操作 – setValues中调用lobCreator.setBlobAsBinaryStrem()。让我们看看具体的BLOB操作在LobCreator 是怎样完成的,我们一般使用DefaultLobCreator作为BLOB操作的驱动:
  

Java代码 

303 public void setBlobAsBinaryStream(   

304         PreparedStatement ps, int paramIndex, InputStream binaryStream, int contentLength)   

305         throws SQLException {   

306     //通过JDBC来完成对BLOB数据的操作,对Oracle,Spring提供了OracleLobHandler来支持BLOB操作。  

307     ps.setBinaryStream(paramIndex, binaryStream, contentLength);   

308     ……..   

309 }  

310 public void setBlobAsBinaryStream(  

311         PreparedStatement ps, int paramIndex, InputStream binaryStream, int contentLength)  

312         throws SQLException {  

313     //通过JDBC来完成对BLOB数据的操作,对Oracle,Spring提供了OracleLobHandler来支持BLOB操作。  

314     ps.setBinaryStream(paramIndex, binaryStream, contentLength);  

315     ........  

316 }  

上面提到的是零零碎碎的Spring JDBC使用的例子,可以看到使用Spring JDBC可以帮助我们完成许多数据库的操作。Spring对数据库操作最基本的服务是通过JdbcTeamplate和他常用的回调函数来实现的,在此之 上,又提供了许多RMDB的操作来帮助我们更便利的对数据库的数据进行操作 – 注意这里没有引入向Hibernate这样的O/R方案。对这些O/R方案的支持,Spring由其他包来完成服务。
 书中还提到关于executeupdate方法之间的区别,update方法返回的是受影响的记录数目的一个计数,并且如果传入参数的话,使用的是 java.sql.PreparedStatement,execute方法总是使用 java.sql.Statement,不接受参数,而且他不返回受影响记录的计数,更适合于创建和丢弃表的语句,而update方法更适合于插入,更新 和删除操作,这也是我们在使用时需要注意的。

本文链接地址:Spring源代码分析()Spring JDBC    转载请保留,谢谢!

您还可能感兴趣的文章:

· Quartz + Spring 简单实现定时任务

· 解决hibernate中使用new Date() 造成oracle date类型时分秒精准度丢失

· 个人关于 spring rmi 配置的理解

· 实现spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器

· spring中配置国际化消息

· Spring Security

下面我们对Spring MVC框架代码进行分析,对于webApplicationContext的相关分析可以参见以前的文档,我们这里着重分析Spring Web MVC框架的实现.我们从分析DispatcherServlet入手:
  

Java代码 

//这里是对DispatcherServlet的初始化方法,根据名字我们很方面的看到对各个Spring MVC主要元素的初始化  

protected void initFrameworkServlet() throws ServletException, BeansException {   

    initMultipartResolver();   

    initLocaleResolver();   

    initThemeResolver();   

    initHandlerMappings();   

    initHandlerAdapters();   

    initHandlerExceptionResolvers();   

    initRequestToViewNameTranslator();   

10     initViewResolvers();   

11 }  

12 //这里是对DispatcherServlet的初始化方法,根据名字我们很方面的看到对各个Spring MVC主要元素的初始化  

13 protected void initFrameworkServlet() throws ServletException, BeansException {  

14     initMultipartResolver();  

15     initLocaleResolver();  

16     initThemeResolver();  

17     initHandlerMappings();  

18     initHandlerAdapters();  

19     initHandlerExceptionResolvers();  

20     initRequestToViewNameTranslator();  

21     initViewResolvers();  

22 }  

看到注解我们知道,这是DispatcherSerlvet的初始化过程,它是在WebApplicationContext已经存在的情况下进行的,也 就意味着在初始化它的时候,IOC容器应该已经工作了,这也是我们在web.xml中配置Spring的时候,需要把DispatcherServlet 的 load-on-startup的属性配置为2的原因。
 对于具体的初始化过程,很容易理解,我们拿initHandlerMappings()来看看:
  

Java代码 

23 private void initHandlerMappings() throws BeansException {   

24     if (this.detectAllHandlerMappings) {   

25          // 这里找到所有在上下文中定义的HandlerMapping,同时把他们排序  

26          // 因为在同一个上下文中可以有不止一个handlerMapping,所以我们把他们都载入到一个链里进行维护和管理  

27         Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(   

28                 getWebApplicationContext(), HandlerMapping.classtruefalse);   

29         if (!matchingBeans.isEmpty()) {   

30             this.handlerMappings = new ArrayList(matchingBeans.values());   

31             // 这里通过order属性来对handlerMapping来在list中排序  

32             Collections.sort(this.handlerMappings, new OrderComparator());   

33         }   

34     }   

35     else {   

36         try {   

37             Object hm = getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);   

38             this.handlerMappings = Collections.singletonList(hm);   

39         }   

40         catch (NoSuchBeanDefinitionException ex) {   

41             // Ignore, we'll add a default HandlerMapping later.  

42         }   

43     }   

44   

45     //如果在上下文中没有定义的话,那么我们使用默认的BeanNameUrlHandlerMapping  

46     if (this.handlerMappings == null) {   

47         this.handlerMappings = getDefaultStrategies(HandlerMapping.class);   

48     ……..   

49     }   

50 }  

51 private void initHandlerMappings() throws BeansException {  

52     if (this.detectAllHandlerMappings) {  

53          // 这里找到所有在上下文中定义的HandlerMapping,同时把他们排序  

54          // 因为在同一个上下文中可以有不止一个handlerMapping,所以我们把他们都载入到一个链里进行维护和管理  

55         Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(  

56                 getWebApplicationContext(), HandlerMapping.class, true, false);  

57         if (!matchingBeans.isEmpty()) {  

58             this.handlerMappings = new ArrayList(matchingBeans.values());  

59             // 这里通过order属性来对handlerMapping来在list中排序  

60             Collections.sort(this.handlerMappings, new OrderComparator());  

61         }  

62     }  

63     else {  

64         try {  

65             Object hm = getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);  

66             this.handlerMappings = Collections.singletonList(hm);  

67         }  

68         catch (NoSuchBeanDefinitionException ex) {  

69             // Ignore, we'll add a default HandlerMapping later.  

70         }  

71     }  

72   

73     //如果在上下文中没有定义的话,那么我们使用默认的BeanNameUrlHandlerMapping  

74     if (this.handlerMappings == null) {  

75         this.handlerMappings = getDefaultStrategies(HandlerMapping.class);  

76     ........  

77     }  

78 }  

怎样获得上下文环境,可以参见我们前面的对IOC容器在web环境中加载的分析。 DispatcherServlet把定义了的所有HandlerMapping都加载了放在一个List里待以后进行使用,这个链的每一个元素都是一个 handlerMapping的配置,而一般每一个handlerMapping可以持有一系列从URL请求到 Spring Controller的映射,比如SimpleUrl
 HandlerMaaping中就定义了一个map来持有这一系列的映射关系。
 DisptcherServlet通过HandlerMapping使得Web应用程序确定一个执行路径,就像我们在HanderMapping中看到的那样,HandlerMapping只是一个借口:
  

Java代码 

79 public interface HandlerMapping {   

80   public static final String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE =   

81                     Conventions.getQualifiedAttributeName(HandlerMapping.class"pathWithinHandlerMapping");   

82       //实际上维护一个HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器  

83     HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;   

84 }  

85 public interface HandlerMapping {  

86   public static final String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE =  

87                     Conventions.getQualifiedAttributeName(HandlerMapping.class, "pathWithinHandlerMapping");  

88       //实际上维护一个HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器  

89     HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;  

90 }  

他的具体实现只需要实现一个接口方法,而这个接口方法返回的是一个HandlerExecutionChain,实际上就是一个执行链,就像在Command模式描述的那样,这个类很简单,就是一个持有一个Interceptor链和一个Controller
  

Java代码 

91 public class HandlerExecutionChain {   

92   

93     private Object handler;   

94   

95     private HandlerInterceptor[] interceptors;   

96       

97     ……..   

98 }  

99 public class HandlerExecutionChain {  

100   

101     private Object handler;  

102   

103     private HandlerInterceptor[] interceptors;  

104   

105     ........  

106 }  

而这些HandlerInterceptor需要我们定义HandlerMapping的时候配置好,比如对具体的 SimpleURLHandlerMapping,他要做的就是根据URL映射的方式注册HandlerInterceptor,自己维护一个放映映射 的handlerMap,当需要匹配Http请求的时候需要使用这个表里的信息来得到执行链。这个注册的过程在IOC容器初始化 SimpleUrlHandlerMapping的时候就被完成了,这样以后的解析才可以用到map里的映射信息,这里的信息和bean文件的信息是等价 的,下面是具体的注册过程:
  

Java代码 

107 protected void registerHandlers(Map urlMap) throws BeansException {   

108     if (urlMap.isEmpty()) {   

109         logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");   

110     }   

111     else {   

112         //这里迭代在SimpleUrlHandlerMapping中定义的所有映射元素  

113         Iterator it = urlMap.keySet().iterator();   

114         while (it.hasNext()) {   

115             //这里取得配置的url  

116             String url = (String) it.next();   

117             //这里根据urlbean定义中取得对应的handler  

118             Object handler = urlMap.get(url);   

119             // Prepend with slash if not already present.  

120             if (!url.startsWith("/")) {   

121                 url = "/" + url;   

122             }   

123             //这里调用AbstractHandlerMapping中的注册过程  

124             registerHandler(url, handler);   

125         }   

126     }   

127 }  

128 protected void registerHandlers(Map urlMap) throws BeansException {  

129     if (urlMap.isEmpty()) {  

130         logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");  

131     }  

132     else {  

133         //这里迭代在SimpleUrlHandlerMapping中定义的所有映射元素  

134         Iterator it = urlMap.keySet().iterator();  

135         while (it.hasNext()) {  

136             //这里取得配置的url  

137             String url = (String) it.next();  

138             //这里根据urlbean定义中取得对应的handler  

139             Object handler = urlMap.get(url);  

140             // Prepend with slash if not already present.  

141             if (!url.startsWith("/")) {  

142                 url = "/" + url;  

143             }  

144             //这里调用AbstractHandlerMapping中的注册过程  

145             registerHandler(url, handler);  

146         }  

147     }  

148 }  

AbstractMappingHandler中的注册代码:
  

Java代码 

149 protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {   

150     //试图从handlerMap中取handler,看看是否已经存在同样的Url映射关系  

151     Object mappedHandler = this.handlerMap.get(urlPath);   

152     if (mappedHandler != null) {   

153     ……..   

154     }   

155   

156     //如果是直接用bean名做映射那就直接从容器中取handler  

157     if (!this.lazyInitHandlers && handler instanceof String) {   

158         String handlerName = (String) handler;   

159         if (getApplicationContext().isSingleton(handlerName)) {   

160             handler = getApplicationContext().getBean(handlerName);   

161         }   

162     }   

163     //或者使用默认的handler.  

164     if (urlPath.equals("/*")) {   

165         setDefaultHandler(handler);   

166     }   

167     else {   

168    //urlhandler的对应关系放到handlerMap中去  

169         this.handlerMap.put(urlPath, handler);   

170         ……..   

171     }   

172 }  

173 protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {  

174     //试图从handlerMap中取handler,看看是否已经存在同样的Url映射关系  

175     Object mappedHandler = this.handlerMap.get(urlPath);  

176     if (mappedHandler != null) {  

177     ........  

178     }  

179   

180     //如果是直接用bean名做映射那就直接从容器中取handler  

181     if (!this.lazyInitHandlers && handler instanceof String) {  

182         String handlerName = (String) handler;  

183         if (getApplicationContext().isSingleton(handlerName)) {  

184             handler = getApplicationContext().getBean(handlerName);  

185         }  

186     }  

187     //或者使用默认的handler.  

188     if (urlPath.equals("/*")) {  

189         setDefaultHandler(handler);  

190     }  

191     else {  

192    //urlhandler的对应关系放到handlerMap中去  

193         this.handlerMap.put(urlPath, handler);  

194         ........  

195     }  

196 }  

handlerMap是持有的一个HashMap,里面就保存了具体的映射信息:
  

Java代码 

197 private final Map handlerMap = new HashMap();  

198 private final Map handlerMap = new HashMap();  

SimpleUrlHandlerMapping对接口HandlerMapping的实现是这样的,这个getHandler根据在初始化的时候就得到的映射表来生成DispatcherServlet需要的执行链
  

Java代码 

199 public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {   

200     //这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping  

201     Object handler = getHandlerInternal(request);   

202     //如果找不到对应的,就使用缺省的handler  

203     if (handler == null) {   

204         handler = this.defaultHandler;   

205     }   

206     //如果缺省的也没有,那就没办法了  

207     if (handler == null) {   

208         return null;   

209     }   

210     // 如果handler不是一个具体的handler,那我们还要到上下文中取  

211     if (handler instanceof String) {   

212         String handlerName = (String) handler;   

213         handler = getApplicationContext().getBean(handlerName);   

214     }   

215     //生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。  

216     return new HandlerExecutionChain(handler, this.adaptedInterceptors);   

217 }  

218 public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  

219     //这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping中  

220     Object handler = getHandlerInternal(request);  

221     //如果找不到对应的,就使用缺省的handler  

222     if (handler == null) {  

223         handler = this.defaultHandler;  

224     }  

225     //如果缺省的也没有,那就没办法了  

226     if (handler == null) {  

227         return null;  

228     }  

229     // 如果handler不是一个具体的handler,那我们还要到上下文中取  

230     if (handler instanceof String) {  

231         String handlerName = (String) handler;  

232         handler = getApplicationContext().getBean(handlerName);  

233     }  

234     //生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。  

235     return new HandlerExecutionChain(handler, this.adaptedInterceptors);  

236 }  

我们看看具体的handler查找过程:
  

Java代码 

237 protected Object getHandlerInternal(HttpServletRequest request) throws Exception {   

238     //这里的HTTP Request传进来的参数进行分析,得到具体的路径信息。  

239     String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);   

240     …….//下面是根据请求信息的查找  

241     return lookupHandler(lookupPath, request);   

242 }   

243   

244 protected Object lookupHandler(String urlPath, HttpServletRequest request) {   

245     // 如果能够直接能在SimpleUrlHandlerMapping的映射表中找到,那最好。  

246     Object handler = this.handlerMap.get(urlPath);   

247     if (handler == null) {   

248         // 这里使用模式来对map中的所有handler进行匹配,调用了Jre中的Matcher类来完成匹配处理。  

249         String bestPathMatch = null;   

250         for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {   

251             String registeredPath = (String) it.next();   

252             if (this.pathMatcher.match(registeredPath, urlPath) &&   

253                             (bestPathMatch == null || bestPathMatch.length() <= registeredPath.length())) {   

254                 //这里根据匹配路径找到最象的一个  

255                 handler = this.handlerMap.get(registeredPath);   

256                 bestPathMatch = registeredPath;   

257             }   

258         }   

259   

260         if (handler != null) {   

261             exposePathWithinMapping(this.pathMatcher.extractPathWithinPattern(bestPathMatch, urlPath), request);   

262         }   

263     }   

264     else {   

265         exposePathWithinMapping(urlPath, request);   

266     }   

267     //  

268     return handler;   

269 }  

270 protected Object getHandlerInternal(HttpServletRequest request) throws Exception {  

271     //这里的HTTP Request传进来的参数进行分析,得到具体的路径信息。  

272     String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);  

273     .......//下面是根据请求信息的查找  

274     return lookupHandler(lookupPath, request);  

275 }  

276   

277 protected Object lookupHandler(String urlPath, HttpServletRequest request) {  

278     // 如果能够直接能在SimpleUrlHandlerMapping的映射表中找到,那最好。  

279     Object handler = this.handlerMap.get(urlPath);  

280     if (handler == null) {  

281         // 这里使用模式来对map中的所有handler进行匹配,调用了Jre中的Matcher类来完成匹配处理。  

282         String bestPathMatch = null;  

283         for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {  

284             String registeredPath = (String) it.next();  

285             if (this.pathMatcher.match(registeredPath, urlPath) &&  

286                             (bestPathMatch == null || bestPathMatch.length() <= registeredPath.length())) {  

287                 //这里根据匹配路径找到最象的一个  

288                 handler = this.handlerMap.get(registeredPath);  

289                 bestPathMatch = registeredPath;  

290             }  

291         }  

292   

293         if (handler != null) {  

294             exposePathWithinMapping(this.pathMatcher.extractPathWithinPattern(bestPathMatch, urlPath), request);  

295         }  

296     }  

297     else {  

298         exposePathWithinMapping(urlPath, request);  

299     }  

300     //  

301     return handler;  

302 }  

我们可以看到,总是在handlerMap这个HashMap中找,当然如果直接找到最好,如果找不到,就看看是不是能通过Match Pattern的模式找,我们一定还记得在配置HnaderMapping的时候是可以通过ANT语法进行配置的,其中的处理就在这里。
 这样可以清楚地看到整个HandlerMapping的初始化过程 – 同时,我们也看到了一个具体的handler映射是怎样被存储和查找的 – 这里生成一个ExecutionChain来储存我们找到的handler和在定义bean的时候定义的Interceptors.
 让我们回到DispatcherServlet,初始化完成以后,实际的对web请求是在doService()方法中处理的,我们知道DispatcherServlet只是一个普通的Servlet:
  

Java代码 

303 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {   

304     …….   

305     //这里把属性信息进行保存  

306     Map attributesSnapshot = null;   

307     if (WebUtils.isIncludeRequest(request)) {   

308         logger.debug("Taking snapshot of request attributes before include");   

309         attributesSnapshot = new HashMap();   

310         Enumeration attrNames = request.getAttributeNames();   

311         while (attrNames.hasMoreElements()) {   

312             String attrName = (String) attrNames.nextElement();   

313             if (this.cleanupAfterInclude || attrName.startsWith(DispatcherServlet.class.getName())) {   

314                 attributesSnapshot.put(attrName, request.getAttribute(attrName));   

315             }   

316         }   

317     }   

318   

319     // Make framework objects available to handlers and view objects.  

320     request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());   

321     request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);   

322     request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);   

323     request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());   

324   

325     try {   

326          //这里使实际的处理入口  

327         doDispatch(request, response);   

328     }   

329     finally {   

330         // Restore the original attribute snapshot, in case of an include.  

331         if (attributesSnapshot != null) {   

332             restoreAttributesAfterInclude(request, attributesSnapshot);   

333         }   

334     }   

335 }  

336 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  

337     .......  

338     //这里把属性信息进行保存  

339     Map attributesSnapshot = null;  

340     if (WebUtils.isIncludeRequest(request)) {  

341         logger.debug("Taking snapshot of request attributes before include");  

342         attributesSnapshot = new HashMap();  

343         Enumeration attrNames = request.getAttributeNames();  

344         while (attrNames.hasMoreElements()) {  

345             String attrName = (String) attrNames.nextElement();  

346             if (this.cleanupAfterInclude || attrName.startsWith(DispatcherServlet.class.getName())) {  

347                 attributesSnapshot.put(attrName, request.getAttribute(attrName));  

348             }  

349         }  

350     }  

351   

352     // Make framework objects available to handlers and view objects.  

353     request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());  

354     request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);  

355     request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);  

356     request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());  

357   

358     try {  

359          //这里使实际的处理入口  

360         doDispatch(request, response);  

361     }  

362     finally {  

363         // Restore the original attribute snapshot, in case of an include.  

364         if (attributesSnapshot != null) {  

365             restoreAttributesAfterInclude(request, attributesSnapshot);  

366         }  

367     }  

368 }  

我们看到,对于请求的处理实际上是让doDispatch()来完成的 – 这个方法很长,但是过程很简单明了:
  

Java代码 

369 protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception {   

370     HttpServletRequest processedRequest = request;   

371     //这是从handlerMapping中得到的执行链  

372     HandlerExecutionChain mappedHandler = null;   

373     int interceptorIndex = -1;   

374       

375     ……..   

376     try {   

377         //我们熟悉的ModelAndView开始出现了。  

378         ModelAndView mv = null;   

379         try {   

380             processedRequest = checkMultipart(request);   

381   

382             // 这是我们得到handler的过程  

383             mappedHandler = getHandler(processedRequest, false);   

384             if (mappedHandler == null || mappedHandler.getHandler() == null) {   

385                 noHandlerFound(processedRequest, response);   

386                 return;   

387             }   

388   

389             // 这里取出执行链中的Interceptor进行前处理  

390             if (mappedHandler.getInterceptors() != null) {   

391                 for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {   

392                     HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];   

393                     if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {   

394                         triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);   

395                         return;   

396                     }   

397                     interceptorIndex = i;   

398                 }   

399             }   

400   

401             //在执行handler之前,用HandlerAdapter先检查一下handler的合法性:是不是按Spring的要求编写的。  

402             HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());   

403             mv = ha.handle(processedRequest, response, mappedHandler.getHandler());   

404   

405             // 这里取出执行链中的Interceptor进行后处理  

406             if (mappedHandler.getInterceptors() != null) {   

407                 for (int i = mappedHandler.getInterceptors().length - 1; i >= 0; i–) {   

408                     HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];   

409                     interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);   

410                 }   

411             }   

412         }   

413           

414         ……..   

415   

416         // Did the handler return a view to render?  

417         //这里对视图生成进行处理  

418         if (mv != null && !mv.wasCleared()) {   

419             render(mv, processedRequest, response);   

420         }   

421         …….   

422 }  

423 protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception {  

424     HttpServletRequest processedRequest = request;  

425     //这是从handlerMapping中得到的执行链  

426     HandlerExecutionChain mappedHandler = null;  

427     int interceptorIndex = -1;  

428   

429     ........  

430     try {  

431         //我们熟悉的ModelAndView开始出现了。  

432         ModelAndView mv = null;  

433         try {  

434             processedRequest = checkMultipart(request);  

435   

436             // 这是我们得到handler的过程  

437             mappedHandler = getHandler(processedRequest, false);  

438             if (mappedHandler == null || mappedHandler.getHandler() == null) {  

439                 noHandlerFound(processedRequest, response);  

440                 return;  

441             }  

442   

443             // 这里取出执行链中的Interceptor进行前处理  

444             if (mappedHandler.getInterceptors() != null) {  

445                 for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {  

446                     HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];  

447                     if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {  

448                         triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);  

449                         return;  

450                     }  

451                     interceptorIndex = i;  

452                 }  

453             }  

454   

455             //在执行handler之前,用HandlerAdapter先检查一下handler的合法性:是不是按Spring的要求编写的。  

456             HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  

457             mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

458   

459             // 这里取出执行链中的Interceptor进行后处理  

460             if (mappedHandler.getInterceptors() != null) {  

461                 for (int i = mappedHandler.getInterceptors().length - 1; i >= 0; i--) {  

462                     HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];  

463                     interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);  

464                 }  

465             }  

466         }  

467   

468         ........  

469   

470         // Did the handler return a view to render?  

471         //这里对视图生成进行处理  

472         if (mv != null && !mv.wasCleared()) {  

473             render(mv, processedRequest, response);  

474         }  

475         .......  

476 }  

我们很清楚的看到和MVC框架紧密相关的代码,比如如何得到和http请求相对应的执行链,怎样执行执行链和怎样把模型数据展现到视图中去。
 先看怎样取得Command对象,对我们来说就是Handler – 下面是getHandler的代码:
  

Java代码 

477 protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {   

478   //ServletContext取得执行链 实际上第一次得到它的时候,我们把它放在ServletContext进行了缓存。  

479   HandlerExecutionChain handler =   

480             (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);   

481     if (handler != null) {   

482         if (!cache) {   

483             request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);   

484         }   

485         return handler;   

486     }   

487     //这里的迭代器迭代的时在initHandlerMapping中载入的上下文所有的HandlerMapping  

488     Iterator it = this.handlerMappings.iterator();   

489     while (it.hasNext()) {   

490         HandlerMapping hm = (HandlerMapping) it.next();   

491         …….   

492         //这里是实际取得handler的过程,在每个HandlerMapping中建立的映射表进行检索得到请求对应的handler  

493         handler = hm.getHandler(request);   

494   

495         //然后把handler存到ServletContext中去进行缓存  

496         if (handler != null) {   

497             if (cache) {   

498                 request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);   

499             }   

500             return handler;   

501         }   

502     }   

503     return null;   

504 }  

505 protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {  

506   //ServletContext取得执行链 实际上第一次得到它的时候,我们把它放在ServletContext进行了缓存。  

507   HandlerExecutionChain handler =  

508             (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);  

509     if (handler != null) {  

510         if (!cache) {  

511             request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);  

512         }  

513         return handler;  

514     }  

515     //这里的迭代器迭代的时在initHandlerMapping中载入的上下文所有的HandlerMapping  

516     Iterator it = this.handlerMappings.iterator();  

517     while (it.hasNext()) {  

518         HandlerMapping hm = (HandlerMapping) it.next();  

519         .......  

520         //这里是实际取得handler的过程,在每个HandlerMapping中建立的映射表进行检索得到请求对应的handler  

521         handler = hm.getHandler(request);  

522   

523         //然后把handler存到ServletContext中去进行缓存  

524         if (handler != null) {  

525             if (cache) {  

526                 request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);  

527             }  

528             return handler;  

529         }  

530     }  

531     return null;  

532 }  

如果在ServletContext中可以取得handler则直接返回,实际上这个handler是缓冲了上次处理的结果 – 总要有第一次把这个handler放到ServletContext中去:
 如果在ServletContext中找不到handler,那就通过持有的handlerMapping生成一个,我们看到它会迭代当前持有的所有的 handlerMapping,因为可以定义不止一个,他们在定义的时候也可以指定顺序,直到找到第一个,然后返回。先找到一个 handlerMapping,然后通过这个handlerMapping返回一个执行链,里面包含了最终的Handler和我们定义的一连串的 Interceptor。具体的我们可以参考上面的SimpleUrlHandlerMapping的代码分析知道getHandler是怎样得到一个 HandlerExecutionChain的。
 得到HandlerExecutionChain以后,我们通过HandlerAdapter对这个Handler的合法性进行判断:
  

Java代码 

533 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {   

534     Iterator it = this.handlerAdapters.iterator();   

535     while (it.hasNext()) {   

536         //同样对持有的所有adapter进行匹配  

537         HandlerAdapter ha = (HandlerAdapter) it.next();   

538         if (ha.supports(handler)) {   

539             return ha;   

540         }   

541     }   

542     ……..   

543 }  

544 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {  

545     Iterator it = this.handlerAdapters.iterator();  

546     while (it.hasNext()) {  

547         //同样对持有的所有adapter进行匹配  

548         HandlerAdapter ha = (HandlerAdapter) it.next();  

549         if (ha.supports(handler)) {  

550             return ha;  

551         }  

552     }  

553     ........  

554 }  

通过判断,我们知道这个handler是不是一个Controller接口的实现,比如对于具体的HandlerAdapter – SimpleControllerHandlerAdapter:
  

Java代码 

555 public class SimpleControllerHandlerAdapter implements HandlerAdapter {   

556       

557     public boolean supports(Object handler) {   

558         return (handler instanceof Controller);   

559     }   

560     …….   

561 }  

562 public class SimpleControllerHandlerAdapter implements HandlerAdapter {  

563   

564     public boolean supports(Object handler) {  

565         return (handler instanceof Controller);  

566     }  

567     .......  

568 }  

简单的判断一下handler是不是实现了Controller接口。这也体现了一种对配置文件进行验证的机制。
 让我们再回到DispatcherServlet看到代码:
  

Java代码 

569 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

570 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

这个就是对handle的具体调用!相当于Command模式里的Command.execute();理所当然的返回一个ModelAndView,下面就是一个对View进行处理的过程:
  

Java代码 

571 if (mv != null && !mv.wasCleared()) {   

572     render(mv, processedRequest, response);   

573 }  

574 if (mv != null && !mv.wasCleared()) {  

575     render(mv, processedRequest, response);  

576 }  

调用的是render方法:
  

Java代码

577 protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)   

578          throws Exception {response.setLocale(locale);   

579   

580      View view = null;   

581      //这里把默认的视图放到ModelAndView中去。  

582      if (!mv.hasView()) {   

583          mv.setViewName(getDefaultViewName(request));   

584      }   

585   

586      if (mv.isReference()) {   

587          // 这里对视图名字进行解析  

588          view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);   

589      …….   

590      }   

591      else {   

592          // 有可能在ModelAndView里已经直接包含了View对象,那我们就直接使用。  

593          view = mv.getView();   

594      ……..   

595      }   

596   

597      //得到具体的View对象以后,我们用它来生成视图。  

598      view.render(mv.getModelInternal(), request, response);   

599  }  

600 protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)  

601          throws Exception {response.setLocale(locale);  

602   

603      View view = null;  

604      //这里把默认的视图放到ModelAndView中去。  

605      if (!mv.hasView()) {  

606          mv.setViewName(getDefaultViewName(request));  

607      }  

608   

609      if (mv.isReference()) {  

610          // 这里对视图名字进行解析  

611          view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);  

612      .......  

613      }  

614      else {  

615          // 有可能在ModelAndView里已经直接包含了View对象,那我们就直接使用。  

616          view = mv.getView();  

617      ........  

618      }  

619   

620      //得到具体的View对象以后,我们用它来生成视图。  

621      view.render(mv.getModelInternal(), request, response);  

622  }  

从整个过程我们看到先在ModelAndView中寻找视图的逻辑名,如果找不到那就使用缺省的视图,如果能够找到视图的名字,那就对他进行解析得到实际 的需要使用的视图对象。还有一种可能就是在ModelAndView中已经包含了实际的视图对象,这个视图对象是可以直接使用的。
 不管怎样,得到一个视图对象以后,通过调用视图对象的render来完成数据的显示过程,我们可以看看具体的JstlView是怎样实现的,我们在JstlView的抽象父类 AbstractView中找到render方法:
  

Java代码

623 public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {   

624     ……   

625     // 这里把所有的相关信息都收集到一个Map  

626     Map mergedModel = new HashMap(this.staticAttributes.size() + (model != null ? model.size() : 0));   

627     mergedModel.putAll(this.staticAttributes);   

628     if (model != null) {   

629         mergedModel.putAll(model);   

630     }   

631   

632     // Expose RequestContext?  

633     if (this.requestContextAttribute != null) {   

634         mergedModel.put(this.requestContextAttribute, createRequestContext(request, mergedModel));   

635     }   

636     //这是实际的展现模型数据到视图的调用。  

637     renderMergedOutputModel(mergedModel, request, response);   

638 }  

639 public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {  

640     ......  

641     // 这里把所有的相关信息都收集到一个Map里  

642     Map mergedModel = new HashMap(this.staticAttributes.size() + (model != null ? model.size() : 0));  

643     mergedModel.putAll(this.staticAttributes);  

644     if (model != null) {  

645         mergedModel.putAll(model);  

646     }  

647   

648     // Expose RequestContext?  

649     if (this.requestContextAttribute != null) {  

650         mergedModel.put(this.requestContextAttribute, createRequestContext(request, mergedModel));  

651     }  

652     //这是实际的展现模型数据到视图的调用。  

653     renderMergedOutputModel(mergedModel, request, response);  

654 }  

注解写的很清楚了,先把所有的数据模型进行整合放到一个Map – mergedModel里,然后调用renderMergedOutputModel();这个renderMergedOutputModel是一个模 板方法,他的实现在InternalResourceView也就是JstlView的父类:
  

Java代码

655 protected void renderMergedOutputModel(   

656        Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {   

657   

658    // Expose the model object as request attributes.  

659    exposeModelAsRequestAttributes(model, request);   

660   

661    // Expose helpers as request attributes, if any.  

662    exposeHelpers(request);   

663   

664    // 这里得到InternalResource定义的内部资源路径。  

665    String dispatcherPath = prepareForRendering(request, response);   

666   

667    //这里把请求转发到前面得到的内部资源路径中去。  

668    RequestDispatcher rd = request.getRequestDispatcher(dispatcherPath);   

669    if (rd == null) {   

670        throw new ServletException(   

671                "Could not get RequestDispatcher for [" + getUrl() + "]: check that this file exists within your WAR");   

672    }   

673    …….   

674 protected void renderMergedOutputModel(  

675        Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {  

676   

677    // Expose the model object as request attributes.  

678    exposeModelAsRequestAttributes(model, request);  

679   

680    // Expose helpers as request attributes, if any.  

681    exposeHelpers(request);  

682   

683    // 这里得到InternalResource定义的内部资源路径。  

684    String dispatcherPath = prepareForRendering(request, response);  

685   

686    //这里把请求转发到前面得到的内部资源路径中去。  

687    RequestDispatcher rd = request.getRequestDispatcher(dispatcherPath);  

688    if (rd == null) {  

689        throw new ServletException(  

690                "Could not get RequestDispatcher for [" + getUrl() + "]: check that this file exists within your WAR");  

691    }  

692    .......  

首先对模型数据进行处理,exposeModelAsRequestAttributes是在AbstractView中实现的,这个方法把 ModelAndView中的模型数据和其他request数据统统放到ServletContext当中去,这样整个模型数据就通过 ServletContext暴露并得到共享使用了:
  

Java代码

693 protected void exposeModelAsRequestAttributes(Map model, HttpServletRequest request) throws Exception {   

694       Iterator it = model.entrySet().iterator();   

695       while (it.hasNext()) {   

696           Map.Entry entry = (Map.Entry) it.next();   

697           ……….   

698           String modelName = (String) entry.getKey();   

699           Object modelValue = entry.getValue();   

700           if (modelValue != null) {   

701               request.setAttribute(modelName, modelValue);   

702           ………..   

703           }   

704           else {   

705               request.removeAttribute(modelName);   

706               …….   

707           }   

708       }   

709   }  

710 protected void exposeModelAsRequestAttributes(Map model, HttpServletRequest request) throws Exception {  

711       Iterator it = model.entrySet().iterator();  

712       while (it.hasNext()) {  

713           Map.Entry entry = (Map.Entry) it.next();  

714           ..........  

715           String modelName = (String) entry.getKey();  

716           Object modelValue = entry.getValue();  

717           if (modelValue != null) {  

718               request.setAttribute(modelName, modelValue);  

719           ...........  

720           }  

721           else {  

722               request.removeAttribute(modelName);  

723               .......  

724           }  

725       }  

726   }  

让我们回到数据处理部分的exposeHelper();这是一个模板方法,其实现在JstlView中实现:
  

Java代码

727 public class JstlView extends InternalResourceView {   

728   

729     private MessageSource jstlAwareMessageSource;   

730   

731   

732     protected void initApplicationContext() {   

733         super.initApplicationContext();   

734         this.jstlAwareMessageSource =   

735                 JstlUtils.getJstlAwareMessageSource(getServletContext(), getApplicationContext());   

736     }   

737   

738     protected void exposeHelpers(HttpServletRequest request) throws Exception {   

739         JstlUtils.exposeLocalizationContext(request, this.jstlAwareMessageSource);   

740     }   

741   

742 }  

743 public class JstlView extends InternalResourceView {  

744   

745     private MessageSource jstlAwareMessageSource;  

746   

747     protected void initApplicationContext() {  

748         super.initApplicationContext();  

749         this.jstlAwareMessageSource =  

750                 JstlUtils.getJstlAwareMessageSource(getServletContext(), getApplicationContext());  

751     }  

752   

753     protected void exposeHelpers(HttpServletRequest request) throws Exception {  

754         JstlUtils.exposeLocalizationContext(request, this.jstlAwareMessageSource);  

755     }  

756   

757 }  

JstlUtils中包含了对于其他而言jstl特殊的数据处理和设置。
 过程是不是很长?我们现在在哪里了?呵呵,我们刚刚完成的事MVCViewrender,对于InternalResourceView的 render 过程比较简单只是完成一个资源的重定向处理。需要做的就是得到实际viewinternalResource路径,然后转发到那个资源中去。怎样得到资 源的路径呢通过调用:
  

Java代码

758 protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response)   

759        throws Exception {   

760   

761    return getUrl();   

762 protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response)  

763        throws Exception {  

764   

765    return getUrl();  

那这个url在哪里生成呢?我们在View相关的代码中没有找到,实际上,他在ViewRosolve的时候就生成了,在UrlBasedViewResolver中:
  

Java代码

766 protected AbstractUrlBasedView buildView(String viewName) throws Exception {   

767     AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());   

768     view.setUrl(getPrefix() + viewName + getSuffix());   

769     String contentType = getContentType();   

770     if (contentType != null) {   

771         view.setContentType(contentType);   

772     }   

773     view.setRequestContextAttribute(getRequestContextAttribute());   

774     view.setAttributesMap(getAttributesMap());   

775     return view;   

776 }  

777 protected AbstractUrlBasedView buildView(String viewName) throws Exception {  

778     AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());  

779     view.setUrl(getPrefix() + viewName + getSuffix());  

780     String contentType = getContentType();  

781     if (contentType != null) {  

782         view.setContentType(contentType);  

783     }  

784     view.setRequestContextAttribute(getRequestContextAttribute());  

785     view.setAttributesMap(getAttributesMap());  

786     return view;  

787 }  

这里是生成View的地方,自然也把生成的url和其他一些和view相关的属性也配置好了。
 那这个ViewResolve是什么时候被调用的呢?哈哈,我们这样又要回到DispatcherServlet中去看看究竟,在DispatcherServlet中:
  

Java代码

788  protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)   

789          throws Exception {   

790   

791      ……..   

792      View view = null;   

793   

794      // 这里设置视图名为默认的名字  

795      if (!mv.hasView()) {   

796          mv.setViewName(getDefaultViewName(request));   

797      }   

798   

799      if (mv.isReference()) {   

800          //这里对视图名进行解析,在解析的过程中根据需要生成实际需要的视图对象。  

801          view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);   

802         ……….   

803      }   

804     ……   

805 }  

806  protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)  

807          throws Exception {  

808   

809      ........  

810      View view = null;  

811   

812      // 这里设置视图名为默认的名字  

813      if (!mv.hasView()) {  

814          mv.setViewName(getDefaultViewName(request));  

815      }  

816   

817      if (mv.isReference()) {  

818          //这里对视图名进行解析,在解析的过程中根据需要生成实际需要的视图对象。  

819          view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);  

820         ..........  

821      }  

822     ......  

823 }  

下面是对视图名进行解析的具体过程:
  

Java代码

824 protected View resolveViewName(String viewName, Map model, Locale locale, HttpServletRequest request)   

825             throws Exception {   

826          //我们有可能不止一个视图解析器  

827         for (Iterator it = this.viewResolvers.iterator(); it.hasNext();) {   

828             ViewResolver viewResolver = (ViewResolver) it.next();   

829             //这里是视图解析器进行解析并生成视图的过程。  

830             View view = viewResolver.resolveViewName(viewName, locale);   

831             if (view != null) {   

832                 return view;   

833             }   

834         }   

835         return null;   

836     }  

837 protected View resolveViewName(String viewName, Map model, Locale locale, HttpServletRequest request)  

838             throws Exception {  

839          //我们有可能不止一个视图解析器  

840         for (Iterator it = this.viewResolvers.iterator(); it.hasNext();) {  

841             ViewResolver viewResolver = (ViewResolver) it.next();  

842             //这里是视图解析器进行解析并生成视图的过程。  

843             View view = viewResolver.resolveViewName(viewName, locale);  

844             if (view != null) {  

845                 return view;  

846             }  

847         }  

848         return null;  

849     }  

这里调用具体的ViewResolver对视图的名字进行解析 – 除了单纯的解析之外,它还根据我们的要求生成了我们实际需要的视图对象。具体的viewResolverbean定义文件中进行定义同时在 initViewResolver()方法中被初始化到viewResolver变量中,我们看看具体的 InternalResourceViewResolver是怎样对视图名进行处理的并生成V视图对象的:对resolveViewName的调用模板在 AbstractCachingViewResolver,
  

Java代码

850 public View resolveViewName(String viewName, Locale locale) throws Exception {   

851     //如果没有打开缓存设置,那创建需要的视图  

852     if (!isCache()) {   

853         logger.warn("View caching is SWITCHED OFF – DEVELOPMENT SETTING ONLY: This can severely impair performance");   

854         return createView(viewName, locale);   

855     }   

856     else {   

857         Object cacheKey = getCacheKey(viewName, locale);   

858         // No synchronization, as we can live with occasional double caching.  

859         synchronized (this.viewCache) {   

860             //这里查找缓存里的视图对象  

861             View view = (View) this.viewCache.get(cacheKey);   

862             if (view == null) {   

863                 //如果在缓存中没有找到,创建一个并把创建的放到缓存中去  

864                 view = createView(viewName, locale);   

865                 this.viewCache.put(cacheKey, view);   

866             ……..   

867             }   

868             return view;   

869         }   

870     }   

871 }  

872 public View resolveViewName(String viewName, Locale locale) throws Exception {  

873     //如果没有打开缓存设置,那创建需要的视图  

874     if (!isCache()) {  

875         logger.warn("View caching is SWITCHED OFF -- DEVELOPMENT SETTING ONLY: This can severely impair performance");  

876         return createView(viewName, locale);  

877     }  

878     else {  

879         Object cacheKey = getCacheKey(viewName, locale);  

880         // No synchronization, as we can live with occasional double caching.  

881         synchronized (this.viewCache) {  

882             //这里查找缓存里的视图对象  

883             View view = (View) this.viewCache.get(cacheKey);  

884             if (view == null) {  

885                 //如果在缓存中没有找到,创建一个并把创建的放到缓存中去  

886                 view = createView(viewName, locale);  

887                 this.viewCache.put(cacheKey, view);  

888             ........  

889             }  

890             return view;  

891         }  

892     }  

893 }  

关于这些createView(),loadView(),buildView()的关系,我们看看Eclipse里的call hiearchy
 然后我们回到view.render中完成数据的最终对httpResponse的写入,比如在AbstractExcelView中的实现:
  

Java代码

894 protected final void renderMergedOutputModel(   

895         Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {   

896     ………   

897     // response.setContentLength(workbook.getBytes().length);  

898     response.setContentType(getContentType());   

899     ServletOutputStream out = response.getOutputStream();   

900     workbook.write(out);   

901     out.flush();   

902 }  

903 protected final void renderMergedOutputModel(  

904         Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {  

905     .........  

906     // response.setContentLength(workbook.getBytes().length);  

907     response.setContentType(getContentType());  

908     ServletOutputStream out = response.getOutputStream();  

909     workbook.write(out);  

910     out.flush();  

911 }  

这样就和我们前面的分析一致起来了:DispatcherServlet在解析视图名的时候就根据要求生成了视图对象,包括在 InternalResourceView中需要使用的url和其他各种和HTTP response相关的属性都会写保持在生成的视图对象中,然后就直接调用视图对象的render来完成数据的展示。
 这就是整个Spring Web MVC框架的大致流程,整个MVC流程由DispatcherServlet来控制。MVC的关键过程包括:
 配置到handler的映射关系和怎样根据请求参数得到对应的handler,Spring中,这是由handlerMapping通过执行链来完成 的,而具体的映射关系我们在bean定义文件中定义并在HandlerMapping载入上下文的时候就被配置好了。然后 DispatcherServlet调用HandlerMapping来得到对应的执行链,最后通过视图来展现模型数据,但我们要注意的是视图对象是在解 析视图名的时候生成配置好的。这些作为核心类的HanderMapping,ViewResolver,View,Handler的紧密协作实现了MVC 的功能。

 

下面我们来看看SpringAOP的一些相关代码是怎么得到Proxy的,让我们我们先看看AOPSpring AOP的一些基本概念:
 Advice
     通知,制定在连接点做什么,在Sping中,他主要描述Spring围绕方法调用注入的额外的行为,Spring提供的通知类型有:
     before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,这些都是Spring AOP定义的接口类,具体的动作实现需要用户程序来完成。
 Pointcut:
     切点,其决定一个advice应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个advice作为目标的一组方法。Spring pointcut通常意味着标示方法,可以选择一组方法调用作为pointcut,Spring提供了具体的切点来给用户使用,比如正则表达式切点 JdkRegexpMethodPointcut通过正则表达式对方法名进行匹配,其通过使用 AbstractJdkRegexpMethodPointcut中的对MethodMatcher接口的实现来完成pointcut功能:
  

Java代码 

public final boolean matches(Method method, Class targetClass) {   

    //这里通过放射得到方法的全名  

    String patt = method.getDeclaringClass().getName() + "." + method.getName();   

    for (int i = 0; i < this.patterns.length; i++) {   

        // 这里是判断是否和方法名是否匹配的代码  

        boolean matched = matches(patt, i);   

        if (matched) {   

            for (int j = 0; j < this.excludedPatterns.length; j++) {   

                boolean excluded = matchesExclusion(patt, j);   

10                 if(excluded) {   

11                     return false;   

12                 }   

13             }   

14             return true;   

15         }   

16     }   

17     return false;   

18 }  

19 public final boolean matches(Method method, Class targetClass) {  

20     //这里通过放射得到方法的全名  

21     String patt = method.getDeclaringClass().getName() + "." + method.getName();  

22     for (int i = 0; i < this.patterns.length; i++) {  

23         // 这里是判断是否和方法名是否匹配的代码  

24         boolean matched = matches(patt, i);  

25         if (matched) {  

26             for (int j = 0; j < this.excludedPatterns.length; j++) {  

27                 boolean excluded = matchesExclusion(patt, j);  

28                 if(excluded) {  

29                     return false;  

30                 }  

31             }  

32             return true;  

33         }  

34     }  

35     return false;  

36 }  

JDKRegexpMethodPointcut中通过JDK中的正则表达式匹配来完成pointcut的最终确定:
  

Java代码 

37 protected boolean matches(String pattern, int patternIndex) {   

38     Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);   

39     return matcher.matches();   

40 }  

41 protected boolean matches(String pattern, int patternIndex) {  

42     Matcher matcher = <a href="http://this.com" title="http://this.com" target="_blank">this.com</a>piledPatterns[patternIndex].matcher(pattern);  

43     return matcher.matches();  

44 }  

Advisor
 当我们完成额外的动作设计(advice)和额外动作插入点的设计(pointcut)以后,我们需要一个对象把他们结合起来,这就是通知器 – advisor,定义应该在哪里应用哪个通知。Advisor的实现有:DefaultPointcutAdvisor他有两个属性advice和 pointcut来让我们配置advicepointcut
 接着我们就可以通过ProxyFactoryBean来配置我们的代理对象和方面行为,在ProxyFactoryBean中有 interceptorNames来配置已经定义好的通知器-advisor,虽然这里的名字叫做interceptNames,但实际上是供我们配置 advisor的地方,具体的代理实现通过JDK Proxy或者CGLIB来完成。因为ProxyFactoryBean是一个FactoryBean,ProxyFactoryBean中我们通过 getObject()可以直接得到代理对象:
  

Java代码 

45 public Object getObject() throws BeansException {   

46     //这里初始化通知器链  

47     initializeAdvisorChain();   

48     if (isSingleton()) {   

49     //根据定义需要生成单件的Proxy  

50         return getSingletonInstance();   

51     }   

52     else {   

53     …….   

54         //这里根据定义需要生成Prototype类型的Proxy  

55         return newPrototypeInstance();   

56     }   

57 }  

58 public Object getObject() throws BeansException {  

59     //这里初始化通知器链  

60     initializeAdvisorChain();  

61     if (isSingleton()) {  

62     //根据定义需要生成单件的Proxy  

63         return getSingletonInstance();  

64     }  

65     else {  

66     .......  

67         //这里根据定义需要生成Prototype类型的Proxy  

68         return newPrototypeInstance();  

69     }  

70 }  

我们看看怎样生成单件的代理对象:
  

Java代码 

71 private synchronized Object getSingletonInstance() {   

72     if (this.singletonInstance == null) {   

73         this.targetSource = freshTargetSource();   

74         if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {   

75             // 这里设置代理对象的接口  

76             setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));   

77         }   

78         // Eagerly initialize the shared singleton instance.  

79         super.setFrozen(this.freezeProxy);   

80         // 注意这里的方法会使用ProxyFactory来生成我们需要的Proxy  

81         this.singletonInstance = getProxy(createAopProxy());   

82         // We must listen to superclass advice change events to recache the singleton  

83         // instance if necessary.  

84         addListener(this);   

85     }   

86     return this.singletonInstance;   

87 }   

88   

89 //使用createAopProxy放回的AopProxy来得到代理对象。  

90 protected Object getProxy(AopProxy aopProxy) {   

91     return aopProxy.getProxy(this.beanClassLoader);   

92 }  

93 private synchronized Object getSingletonInstance() {  

94     if (this.singletonInstance == null) {  

95         this.targetSource = freshTargetSource();  

96         if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {  

97             // 这里设置代理对象的接口  

98             setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));  

99         }  

100         // Eagerly initialize the shared singleton instance.  

101         super.setFrozen(this.freezeProxy);  

102         // 注意这里的方法会使用ProxyFactory来生成我们需要的Proxy  

103         this.singletonInstance = getProxy(createAopProxy());  

104         // We must listen to superclass advice change events to recache the singleton  

105         // instance if necessary.  

106         addListener(this);  

107     }  

108     return this.singletonInstance;  

109 }  

110   

111 //使用createAopProxy放回的AopProxy来得到代理对象。  

112 protected Object getProxy(AopProxy aopProxy) {  

113     return aopProxy.getProxy(this.beanClassLoader);  

114 }  

ProxyFactoryBean的父类是AdvisedSupportSpring使用AopProxy接口把AOP代理的实现与框架的其他部分分离 开来;在AdvisedSupport中通过这样的方式来得到AopProxy,当然这里需要得到AopProxyFactory的帮助 – 下面我们看到Spring为我们提供的实现,来帮助我们方便的从JDK或者cglib中得到我们想要的代理对象:
  

Java代码 

115 protected synchronized AopProxy createAopProxy() {   

116     if (!this.isActive) {   

117         activate();   

118     }   

119     return getAopProxyFactory().createAopProxy(this);   

120 }  

121 protected synchronized AopProxy createAopProxy() {  

122     if (!this.isActive) {  

123         activate();  

124     }  

125     return getAopProxyFactory().createAopProxy(this);  

126 }  

而在ProxyConfig中对使用的AopProxyFactory做了定义:
  

Java代码 

127 //这个DefaultAopProxyFactorySpring用来生成AopProxy的地方,  

128 //当然了它包含JDKCglib两种实现方式。  

129 private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();  

130 //这个DefaultAopProxyFactorySpring用来生成AopProxy的地方,  

131 //当然了它包含JDKCglib两种实现方式。  

132 private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();  

其中在DefaultAopProxyFactory中是这样生成AopProxy的:
  

Java代码 

133 public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {   

134     //首先考虑使用cglib来实现代理对象,当然如果同时目标对象不是接口的实现类的话  

135     if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||   

136         advisedSupport.getProxiedInterfaces().length == 0) {   

137         //这里判断如果不存在cglib库,直接抛出异常。  

138         if (!cglibAvailable) {   

139             throw new AopConfigException(   

140                     "Cannot proxy target class because CGLIB2 is not available. " +   

141                     "Add CGLIB to the class path or specify proxy interfaces.");   

142         }   

143         // 这里使用Cglib来生成Proxy,如果target不是接口的实现的话,返回cglib类型的AopProxy  

144         return CglibProxyFactory.createCglibProxy(advisedSupport);   

145     }   

146     else {   

147         // 这里使用JDK来生成Proxy,返回JDK类型的AopProxy  

148         return new JdkDynamicAopProxy(advisedSupport);   

149     }   

150 }  

151 public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {  

152     //首先考虑使用cglib来实现代理对象,当然如果同时目标对象不是接口的实现类的话  

153     if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||  

154         advisedSupport.getProxiedInterfaces().length == 0) {  

155         //这里判断如果不存在cglib库,直接抛出异常。  

156         if (!cglibAvailable) {  

157             throw new AopConfigException(  

158                     "Cannot proxy target class because CGLIB2 is not available. " +  

159                     "Add CGLIB to the class path or specify proxy interfaces.");  

160         }  

161         // 这里使用Cglib来生成Proxy,如果target不是接口的实现的话,返回cglib类型的AopProxy  

162         return CglibProxyFactory.createCglibProxy(advisedSupport);  

163     }  

164     else {  

165         // 这里使用JDK来生成Proxy,返回JDK类型的AopProxy  

166         return new JdkDynamicAopProxy(advisedSupport);  

167     }  

168 }  

于是我们就可以看到其中的代理对象可以由JDK或者Cglib来生成,我们看到JdkDynamicAopProxy类和Cglib2AopProxy都 实现的是AopProxy的接口,在JdkDynamicAopProxy实现中我们可以看到Proxy是怎样生成的:
  

Java代码 

169 public Object getProxy(ClassLoader classLoader) {   

170     if (logger.isDebugEnabled()) {   

171         Class targetClass = this.advised.getTargetSource().getTargetClass();   

172         logger.debug("Creating JDK dynamic proxy" +   

173                 (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));   

174     }   

175     Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);   

176     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);   

177     //这里我们调用JDK Proxy来生成需要的Proxy实例  

178     return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);   

179 }  

180 public Object getProxy(ClassLoader classLoader) {  

181     if (logger.isDebugEnabled()) {  

182         Class targetClass = this.advised.getTargetSource().getTargetClass();  

183         logger.debug("Creating JDK dynamic proxy" +  

184                 (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));  

185     }  

186     Class[] proxiedInterfaces = <a href="http://AopProxyUtils.com" title="http://AopProxyUtils.com" target="_blank">AopProxyUtils.com</a>pleteProxiedInterfaces(this.advised);  

187     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);  

188     //这里我们调用JDK Proxy来生成需要的Proxy实例  

189     return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);  

190 }  

这样用Proxy包装target之后,通过ProxyFactoryBean得到对其方法的调用就被Proxy拦截了, ProxyFactoryBeangetObject()方法得到的实际上是一个Proxy了,我们的target对象已经被封装了。对 ProxyFactoryBean这个工厂bean而言,其生产出来的对象是封装了目标对象的代理对象。

 

我们看看Spring中的事务处理的代码,使用Spring管理事务有声明式和编程式两种方式,声明式事务处理通过AOP的实现把事物管理代码作为 方面封装来横向插入到业务代码中,使得事务管理代码和业务代码解藕。在这种方式我们结合IoC容器和Spirng已有的FactoryBean来对事务管 理进行属性配置,比如传播行为,隔离级别等。其中最简单的方式就是通过配置TransactionProxyFactoryBean来实现声明式事物;
 在整个源代码分析中,我们可以大致可以看到Spring实现声明式事物管理有这么几个部分:

    * 对在上下文中配置的属性的处理,这里涉及的类是TransactionAttributeSourceAdvisor,这是一个通知器,用它来对属性值进 行处理,属性信息放在TransactionAttribute中来使用,而这些属性的处理往往是和对切入点的处理是结合起来的。对属性的处理放在类 TransactionAttributeSource中完成。
     * 创建事物的过程,这个过程是委托给具体的事物管理器来创建的,但Spring通过TransactionStatus来传递相关的信息。
     * 对事物的处理通过对相关信息的判断来委托给具体的事物管理器完成。

我们下面看看具体的实现,在TransactionFactoryBean中:
  

Java代码 

public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean   

        implements FactoryBean, BeanFactoryAware {   

//这里是Spring事务处理而使用的AOP拦截器,中间封装了Spring对事务处理的代码来支持声明式事务处理的实现  

    private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();   

  

    private Pointcut pointcut;   

  

//这里SpringTransactionManager注入到TransactionInterceptor中去  

    public void setTransactionManager(PlatformTransactionManager transactionManager) {   

10         this.transactionInterceptor.setTransactionManager(transactionManager);   

11     }   

12   

13 //这里把在bean配置文件中读到的事务管理的属性信息注入到TransactionInterceptor中去  

14     public void setTransactionAttributes(Properties transactionAttributes) {   

15         this.transactionInterceptor.setTransactionAttributes(transactionAttributes);   

16     }   

17   

18     ………中间省略了其他一些方法…….   

19   

20     //这里创建Spring AOP对事务处理的Advisor  

21     protected Object createMainInterceptor() {   

22         this.transactionInterceptor.afterPropertiesSet();   

23         if (this.pointcut != null) {   

24             //这里使用默认的通知器  

25             return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);   

26         }   

27         else {   

28             // 使用上面定义好的TransactionInterceptor作为拦截器,同时使用TransactionAttributeSourceAdvisor  

29             return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);   

30         }   

31     }   

32 }  

33 public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean  

34         implements FactoryBean, BeanFactoryAware {  

35 //这里是Spring事务处理而使用的AOP拦截器,中间封装了Spring对事务处理的代码来支持声明式事务处理的实现  

36     private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();  

37   

38     private Pointcut pointcut;  

39   

40 //这里SpringTransactionManager注入到TransactionInterceptor中去  

41     public void setTransactionManager(PlatformTransactionManager transactionManager) {  

42         this.transactionInterceptor.setTransactionManager(transactionManager);  

43     }  

44   

45 //这里把在bean配置文件中读到的事务管理的属性信息注入到TransactionInterceptor中去  

46     public void setTransactionAttributes(Properties transactionAttributes) {  

47         this.transactionInterceptor.setTransactionAttributes(transactionAttributes);  

48     }  

49   

50     .........中间省略了其他一些方法.......  

51   

52     //这里创建Spring AOP对事务处理的Advisor  

53     protected Object createMainInterceptor() {  

54         this.transactionInterceptor.afterPropertiesSet();  

55         if (this.pointcut != null) {  

56             //这里使用默认的通知器  

57             return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);  

58         }  

59         else {  

60             // 使用上面定义好的TransactionInterceptor作为拦截器,同时使用TransactionAttributeSourceAdvisor  

61             return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);  

62         }  

63     }  

64 }  

那什么时候SpringTransactionInterceptor被注入到Spring AOP中成为Advisor中的一部分呢?我们看到在TransactionProxyFactoryBean中,这个方法在IOC初始化bean的时候被执行:
  

Java代码 

65 public void afterPropertiesSet() {   

66     …….   

67     //TransactionProxyFactoryBean实际上使用ProxyFactory完成AOP的基本功能。  

68     ProxyFactory proxyFactory = new ProxyFactory();   

69   

70     if (this.preInterceptors != null) {   

71         for (int i = 0; i < this.preInterceptors.length; i++) {   

72             proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.preInterceptors[i]));   

73         }   

74     }   

75   

76     //这里是Spring加入通知器的地方  

77     //有两种通知器可以被加入DefaultPointcutAdvisor或者TransactionAttributeSourceAdvisor  

78     //这里把Spring处理声明式事务处理的AOP代码都放到ProxyFactory中去,怎样加入advisor我们可以参考ProxyFactory的父类AdvisedSupport()  

79     //由它来维护一个advice的链表,通过这个链表的增删改来抽象我们对整个通知器配置的增删改操作。  

80     proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));   

81   

82     if (this.postInterceptors != null) {   

83         for (int i = 0; i < this.postInterceptors.length; i++) {   

84             proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.postInterceptors[i]));   

85         }   

86     }   

87   

88     proxyFactory.copyFrom(this);   

89       

90     //这里创建AOP的目标源  

91     TargetSource targetSource = createTargetSource(this.target);   

92     proxyFactory.setTargetSource(targetSource);   

93   

94     if (this.proxyInterfaces != null) {   

95         proxyFactory.setInterfaces(this.proxyInterfaces);   

96     }   

97     else if (!isProxyTargetClass()) {   

98         proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass()));   

99     }   

100   

101     this.proxy = getProxy(proxyFactory);   

102 }  

103 public void afterPropertiesSet() {  

104     .......  

105     //TransactionProxyFactoryBean实际上使用ProxyFactory完成AOP的基本功能。  

106     ProxyFactory proxyFactory = new ProxyFactory();  

107   

108     if (this.preInterceptors != null) {  

109         for (int i = 0; i < this.preInterceptors.length; i++) {  

110             proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.preInterceptors[i]));  

111         }  

112     }  

113   

114     //这里是Spring加入通知器的地方  

115     //有两种通知器可以被加入DefaultPointcutAdvisor或者TransactionAttributeSourceAdvisor  

116     //这里把Spring处理声明式事务处理的AOP代码都放到ProxyFactory中去,怎样加入advisor我们可以参考ProxyFactory的父类AdvisedSupport()  

117     //由它来维护一个advice的链表,通过这个链表的增删改来抽象我们对整个通知器配置的增删改操作。  

118     proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));  

119   

120     if (this.postInterceptors != null) {  

121         for (int i = 0; i < this.postInterceptors.length; i++) {  

122             proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(this.postInterceptors[i]));  

123         }  

124     }  

125   

126     proxyFactory.copyFrom(this);  

127   

128     //这里创建AOP的目标源  

129     TargetSource targetSource = createTargetSource(this.target);  

130     proxyFactory.setTargetSource(targetSource);  

131   

132     if (this.proxyInterfaces != null) {  

133         proxyFactory.setInterfaces(this.proxyInterfaces);  

134     }  

135     else if (!isProxyTargetClass()) {  

136         proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass()));  

137     }  

138   

139     this.proxy = getProxy(proxyFactory);  

140 }  

Spring 已经定义了一个transctionInterceptor作为拦截器或者AOP advice的实现,在IOC容器中定义的其他属性比如transactionManager和事务管理的属性都会传到已经定义好的 TransactionInterceptor那里去进行处理。以上反映了基本的Spring AOP的定义过程,其中pointcutadvice都已经定义好,同时也通过通知器配置到ProxyFactory中去了。
 下面让我们回到TransactionProxyFactoryBean中看看TransactionAttributeSourceAdvisor是怎 样定义的,这样我们可以理解具体的属性是怎样起作用,这里我们分析一下类TransactionAttributeSourceAdvisor:
  

Java代码 

141 public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {   

142     //和其他Advisor一样,同样需要定义AOP中的用到的InterceptorPointcut  

143     //Interceptor使用传进来的TransactionInterceptor  

144     //而对于pointcut,这里定义了一个内部类,参见下面的代码    

145     private TransactionInterceptor transactionInterceptor;   

146   

147     private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut();   

148       

149     ………   

150     //定义的PointCut内部类  

151         private class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {   

152        …….   

153       //方法匹配的实现,使用了TransactionAttributeSource  

154         public boolean matches(Method method, Class targetClass) {   

155             TransactionAttributeSource tas = getTransactionAttributeSource();   

156             //这里使用TransactionAttributeSource来对配置属性进行处理  

157             return (tas != null && tas.getTransactionAttribute(method, targetClass) != null);   

158         }   

159     ……..省略了equal,hashcode,tostring的代码   

160     }  

161 public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor {  

162     //和其他Advisor一样,同样需要定义AOP中的用到的InterceptorPointcut  

163     //Interceptor使用传进来的TransactionInterceptor  

164     //而对于pointcut,这里定义了一个内部类,参见下面的代码  

165     private TransactionInterceptor transactionInterceptor;  

166   

167     private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut();  

168   

169     .........  

170     //定义的PointCut内部类  

171         private class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {  

172        .......  

173       //方法匹配的实现,使用了TransactionAttributeSource类  

174         public boolean matches(Method method, Class targetClass) {  

175             TransactionAttributeSource tas = getTransactionAttributeSource();  

176             //这里使用TransactionAttributeSource来对配置属性进行处理  

177             return (tas != null && tas.getTransactionAttribute(method, targetClass) != null);  

178         }  

179     ........省略了equal,hashcode,tostring的代码  

180     }  

这里我们看看属性值是怎样被读入的:AbstractFallbackTransactionAttributeSource负责具体的属性读入任务,我 们可以有两种读入方式,比如annotation和直接配置.我们下面看看直接配置的读入方式,在Spring中同时对读入的属性值进行了缓存处理,这是 一个decorator模式:
  

Java代码 

181 public final TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {   

182     //这里先查一下缓存里有没有事务管理的属性配置,如果有从缓存中取得TransactionAttribute  

183     Object cacheKey = getCacheKey(method, targetClass);   

184     Object cached = this.cache.get(cacheKey);   

185     if (cached != null) {   

186         if (cached == NULL_TRANSACTION_ATTRIBUTE) {   

187             return null;   

188         }   

189         else {   

190             return (TransactionAttribute) cached;   

191         }   

192     }   

193     else {   

194         // 这里通过对方法和目标对象的信息来计算事务缓存属性  

195         TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);   

196         //把得到的事务缓存属性存到缓存中,下次可以直接从缓存中取得。  

197         if (txAtt == null) {   

198             this.cache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);   

199         }   

200         else {   

201             ………..   

202             this.cache.put(cacheKey, txAtt);   

203         }   

204         return txAtt;   

205     }   

206 }  

207 public final TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {  

208     //这里先查一下缓存里有没有事务管理的属性配置,如果有从缓存中取得TransactionAttribute  

209     Object cacheKey = getCacheKey(method, targetClass);  

210     Object cached = this.cache.get(cacheKey);  

211     if (cached != null) {  

212         if (cached == NULL_TRANSACTION_ATTRIBUTE) {  

213             return null;  

214         }  

215         else {  

216             return (TransactionAttribute) cached;  

217         }  

218     }  

219     else {  

220         // 这里通过对方法和目标对象的信息来计算事务缓存属性  

221         TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);  

222         //把得到的事务缓存属性存到缓存中,下次可以直接从缓存中取得。  

223         if (txAtt == null) {  

224             this.cache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);  

225         }  

226         else {  

227             ...........  

228             this.cache.put(cacheKey, txAtt);  

229         }  

230         return txAtt;  

231     }  

232 }  

别急,基本的处理在computeTransactionAttribute()中:
  

Java代码 

233 private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) {   

234     //这里检测是不是public方法  

235     if(allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {   

236         return null;   

237     }   

238       

239     Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);   

240       

241     // First try is the method in the target class.  

242     TransactionAttribute txAtt = findTransactionAttribute(findAllAttributes(specificMethod));   

243     if (txAtt != null) {   

244         return txAtt;   

245     }   

246   

247     // Second try is the transaction attribute on the target class.  

248     txAtt = findTransactionAttribute(findAllAttributes(specificMethod.getDeclaringClass()));   

249     if (txAtt != null) {   

250         return txAtt;   

251     }   

252   

253     if (specificMethod != method) {   

254         // Fallback is to look at the original method.  

255         txAtt = findTransactionAttribute(findAllAttributes(method));   

256         if (txAtt != null) {   

257             return txAtt;   

258         }   

259         // Last fallback is the class of the original method.  

260         return findTransactionAttribute(findAllAttributes(method.getDeclaringClass()));   

261     }   

262     return null;   

263 }  

264 private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) {  

265     //这里检测是不是public方法  

266     if(allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {  

267         return null;  

268     }  

269   

270     Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);  

271   

272     // First try is the method in the target class.  

273     TransactionAttribute txAtt = findTransactionAttribute(findAllAttributes(specificMethod));  

274     if (txAtt != null) {  

275         return txAtt;  

276     }  

277   

278     // Second try is the transaction attribute on the target class.  

279     txAtt = findTransactionAttribute(findAllAttributes(specificMethod.getDeclaringClass()));  

280     if (txAtt != null) {  

281         return txAtt;  

282     }  

283   

284     if (specificMethod != method) {  

285         // Fallback is to look at the original method.  

286         txAtt = findTransactionAttribute(findAllAttributes(method));  

287         if (txAtt != null) {  

288             return txAtt;  

289         }  

290         // Last fallback is the class of the original method.  

291         return findTransactionAttribute(findAllAttributes(method.getDeclaringClass()));  

292     }  

293     return null;  

294 }  

经过一系列的尝试我们可以通过findTransactionAttribute()通过调用findAllAttribute()得到TransactionAttribute的对象,如果返回的是null,这说明该方法不是我们需要事务处理的方法。
 在完成把需要的通知器加到ProxyFactory中去的基础上,我们看看具体的看事务处理代码怎样起作用,在TransactionInterceptor中:
  

Java代码 

295 public Object invoke(final MethodInvocation invocation) throws Throwable {   

296     //这里得到目标对象  

297     Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);   

298   

299     //这里同样的通过判断是否能够得到TransactionAttribute来决定是否对当前方法进行事务处理,有可能该属性已经被缓存,  

300     //具体可以参考上面对getTransactionAttribute的分析,同样是通过TransactionAttributeSource  

301     final TransactionAttribute txAttr =   

302             getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);   

303     final String joinpointIdentification = methodIdentification(invocation.getMethod());   

304   

305     //这里判断我们使用了什么TransactionManager  

306     if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {   

307         // 这里创建事务,同时把创建事务过程中得到的信息放到TransactionInfo中去  

308         TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);   

309         Object retVal = null;   

310         try {   

311               retVal = invocation.proceed();   

312         }   

313         catch (Throwable ex) {   

314             // target invocation exception  

315             completeTransactionAfterThrowing(txInfo, ex);   

316             throw ex;   

317         }   

318         finally {   

319             cleanupTransactionInfo(txInfo);   

320         }   

321         commitTransactionAfterReturning(txInfo);   

322         return retVal;   

323     }   

324   

325     else {   

326         // 使用的是Spring定义的PlatformTransactionManager同时实现了回调接口,我们通过其回调函数完成事务处理,就像我们使用编程式事务处理一样。  

327         try {   

328             Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,   

329                     new TransactionCallback() {   

330                         public Object doInTransaction(TransactionStatus status) {   

331                             //同样的需要一个TransactonInfo  

332                             TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);   

333                             try {   

334                                 return invocation.proceed();   

335                             }   

336                          …..这里省去了异常处理和事务信息的清理代码   

337                     });   

338          ………..   

339     }   

340 }  

341 public Object invoke(final MethodInvocation invocation) throws Throwable {  

342     //这里得到目标对象  

343     Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null);  

344   

345     //这里同样的通过判断是否能够得到TransactionAttribute来决定是否对当前方法进行事务处理,有可能该属性已经被缓存,  

346     //具体可以参考上面对getTransactionAttribute的分析,同样是通过TransactionAttributeSource  

347     final TransactionAttribute txAttr =  

348             getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);  

349     final String joinpointIdentification = methodIdentification(invocation.getMethod());  

350   

351     //这里判断我们使用了什么TransactionManager  

352     if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {  

353         // 这里创建事务,同时把创建事务过程中得到的信息放到TransactionInfo中去  

354         TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointIdentification);  

355         Object retVal = null;  

356         try {  

357               retVal = invocation.proceed();  

358         }  

359         catch (Throwable ex) {  

360             // target invocation exception  

361             completeTransactionAfterThrowing(txInfo, ex);  

362             throw ex;  

363         }  

364         finally {  

365             cleanupTransactionInfo(txInfo);  

366         }  

367         commitTransactionAfterReturning(txInfo);  

368         return retVal;  

369     }  

370   

371     else {  

372         // 使用的是Spring定义的PlatformTransactionManager同时实现了回调接口,我们通过其回调函数完成事务处理,就像我们使用编程式事务处理一样。  

373         try {  

374             Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,  

375                     new TransactionCallback() {  

376                         public Object doInTransaction(TransactionStatus status) {  

377                             //同样的需要一个TransactonInfo  

378                             TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);  

379                             try {  

380                                 return invocation.proceed();  

381                             }  

382                          .....这里省去了异常处理和事务信息的清理代码  

383                     });  

384          ...........  

385     }  

386 }  

这里面涉及到事务的创建,我们可以在TransactionAspectSupport实现的事务管理代码:
  

Java代码 

387 protected TransactionInfo createTransactionIfNecessary(   

388         TransactionAttribute txAttr, final String joinpointIdentification) {   

389   

390     // If no name specified, apply method identification as transaction name.  

391     if (txAttr != null && txAttr.getName() == null) {   

392         txAttr = new DelegatingTransactionAttribute(txAttr) {   

393             public String getName() {   

394                 return joinpointIdentification;   

395             }   

396         };   

397     }   

398   

399     TransactionStatus status = null;   

400     if (txAttr != null) {   

401     //这里使用了我们定义好的事务配置信息,有事务管理器来创建事务,同时返回TransactionInfo  

402         status = getTransactionManager().getTransaction(txAttr);   

403     }   

404     return prepareTransactionInfo(txAttr, joinpointIdentification, status);   

405 }  

406 protected TransactionInfo createTransactionIfNecessary(  

407         TransactionAttribute txAttr, final String joinpointIdentification) {  

408   

409     // If no name specified, apply method identification as transaction name.  

410     if (txAttr != null && txAttr.getName() == null) {  

411         txAttr = new DelegatingTransactionAttribute(txAttr) {  

412             public String getName() {  

413                 return joinpointIdentification;  

414             }  

415         };  

416     }  

417   

418     TransactionStatus status = null;  

419     if (txAttr != null) {  

420     //这里使用了我们定义好的事务配置信息,有事务管理器来创建事务,同时返回TransactionInfo  

421         status = getTransactionManager().getTransaction(txAttr);  

422     }  

423     return prepareTransactionInfo(txAttr, joinpointIdentification, status);  

424 }  

首先通过TransactionManager得到需要的事务,事务的创建根据我们定义的事务配置决定,在 AbstractTransactionManager中给出一个标准的创建过程,当然创建什么样的事务还是需要具体的 PlatformTransactionManager来决定,但这里给出了创建事务的模板:
  

Java代码 

425 public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {   

426     Object transaction = doGetTransaction();   

427     ……   

428   

429     if (definition == null) {   

430         //如果事务信息没有被配置,我们使用Spring默认的配置方式  

431         definition = new DefaultTransactionDefinition();   

432     }   

433   

434     if (isExistingTransaction(transaction)) {   

435         // Existing transaction found -> check propagation behavior to find out how to behave.  

436         return handleExistingTransaction(definition, transaction, debugEnabled);   

437     }   

438   

439     // Check definition settings for new transaction.  

440     //下面就是使用配置信息来创建我们需要的事务;比如传播属性和同步属性等  

441     //最后把创建过程中的信息收集起来放到TransactionStatus中返回;    

442     if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {   

443         throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());   

444     }   

445   

446     // No existing transaction found -> check propagation behavior to find out how to behave.  

447     if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {   

448         throw new IllegalTransactionStateException(   

449                 "Transaction propagation 'mandatory' but no existing transaction found");   

450     }   

451     else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||   

452             definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||   

453         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {   

454         //这里是事务管理器创建事务的地方,并将创建过程中得到的信息放到TransactionStatus中去,包括创建出来的事务  

455         doBegin(transaction, definition);   

456         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);   

457         return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);   

458     }   

459     else {   

460         boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);   

461         return newTransactionStatus(definition, nullfalse, newSynchronization, debugEnabled, null);   

462     }   

463 }  

464 public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {  

465     Object transaction = doGetTransaction();  

466     ......  

467   

468     if (definition == null) {  

469         //如果事务信息没有被配置,我们使用Spring默认的配置方式  

470         definition = new DefaultTransactionDefinition();  

471     }  

472   

473     if (isExistingTransaction(transaction)) {  

474         // Existing transaction found -> check propagation behavior to find out how to behave.  

475         return handleExistingTransaction(definition, transaction, debugEnabled);  

476     }  

477   

478     // Check definition settings for new transaction.  

479     //下面就是使用配置信息来创建我们需要的事务;比如传播属性和同步属性等  

480     //最后把创建过程中的信息收集起来放到TransactionStatus中返回;  

481     if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {  

482         throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());  

483     }  

484   

485     // No existing transaction found -> check propagation behavior to find out how to behave.  

486     if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {  

487         throw new IllegalTransactionStateException(  

488                 "Transaction propagation 'mandatory' but no existing transaction found");  

489     }  

490     else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||  

491             definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||  

492         definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {  

493         //这里是事务管理器创建事务的地方,并将创建过程中得到的信息放到TransactionStatus中去,包括创建出来的事务  

494         doBegin(transaction, definition);  

495         boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);  

496         return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);  

497     }  

498     else {  

499         boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);  

500         return newTransactionStatus(definition, null, false, newSynchronization, debugEnabled, null);  

501     }  

502 }  

接着通过调用prepareTransactionInfo完成事务创建的准备,创建过程中得到的信息存储在TransactionInfo对象中进行传递同时把信息和当前线程绑定;
  

Java代码 

503 protected TransactionInfo prepareTransactionInfo(   

504         TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {   

505   

506     TransactionInfo txInfo = new TransactionInfo(txAttr, joinpointIdentification);   

507     if (txAttr != null) {   

508     …..   

509         // 同样的需要把在getTransaction中得到的TransactionStatus放到TransactionInfo中来。  

510         txInfo.newTransactionStatus(status);   

511     }   

512     else {   

513     …….   

514    }   

515   

516     // 绑定事务创建信息到当前线程  

517     txInfo.bindToThread();   

518     return txInfo;   

519 }  

520 protected TransactionInfo prepareTransactionInfo(  

521         TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {  

522   

523     TransactionInfo txInfo = new TransactionInfo(txAttr, joinpointIdentification);  

524     if (txAttr != null) {  

525     .....  

526         // 同样的需要把在getTransaction中得到的TransactionStatus放到TransactionInfo中来。  

527         txInfo.newTransactionStatus(status);  

528     }  

529     else {  

530     .......  

531    }  

532   

533     // 绑定事务创建信息到当前线程  

534     txInfo.bindToThread();  

535     return txInfo;  

536 }  

将创建事务的信息返回,然后看到其他的事务管理代码:
  

Java代码 

537 protected void commitTransactionAfterReturning(TransactionInfo txInfo) {   

538     if (txInfo != null && txInfo.hasTransaction()) {   

539         if (logger.isDebugEnabled()) {   

540             logger.debug("Invoking commit for transaction on " + txInfo.getJoinpointIdentification());   

541         }   

542         this.transactionManager.commit(txInfo.getTransactionStatus());   

543     }   

544 }  

545 protected void commitTransactionAfterReturning(TransactionInfo txInfo) {  

546     if (txInfo != null && txInfo.hasTransaction()) {  

547         if (logger.isDebugEnabled()) {  

548             logger.debug("Invoking commit for transaction on " + txInfo.getJoinpointIdentification());  

549         }  

550         <a href="http://this.transactionManager.com" title="http://this.transactionManager.com" target="_blank">this.transactionManager.com</a>mit(txInfo.getTransactionStatus());  

551     }  

552 }  

通过transactionManager对事务进行处理,包括异常抛出和正常的提交事务,具体的事务管理器由用户程序设定。
  

Java代码 

553 protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {   

554     if (txInfo != null && txInfo.hasTransaction()) {   

555         if (txInfo.transactionAttribute.rollbackOn(ex)) {   

556             ……   

557             try {   

558                 this.transactionManager.rollback(txInfo.getTransactionStatus());   

559             }   

560             ……….   

561   }   

562         else {   

563             ………   

564             try {   

565                 this.transactionManager.commit(txInfo.getTransactionStatus());   

566             }   

567    ………..   

568 }   

569   

570 protected void commitTransactionAfterReturning(TransactionInfo txInfo) {   

571     if (txInfo != null && txInfo.hasTransaction()) {   

572         ……   

573         this.transactionManager.commit(txInfo.getTransactionStatus());   

574     }   

575 }  

576 protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {  

577     if (txInfo != null && txInfo.hasTransaction()) {  

578         if (txInfo.transactionAttribute.rollbackOn(ex)) {  

579             ......  

580             try {  

581                 this.transactionManager.rollback(txInfo.getTransactionStatus());  

582             }  

583             ..........  

584   }  

585         else {  

586             .........  

587             try {  

588                 <a href="http://this.transactionManager.com" title="http://this.transactionManager.com" target="_blank">this.transactionManager.com</a>mit(txInfo.getTransactionStatus());  

589             }  

590    ...........  

591 }  

592   

593 protected void commitTransactionAfterReturning(TransactionInfo txInfo) {  

594     if (txInfo != null && txInfo.hasTransaction()) {  

595         ......  

596         <a href="http://this.transactionManager.com" title="http://this.transactionManager.com" target="_blank">this.transactionManager.com</a>mit(txInfo.getTransactionStatus());  

597     }  

598 }  

Spring通过以上代码对transactionManager进行事务处理的过程进行了AOP包装,到这里我们看到为了方便客户实现声明式的事务处理,Spring还是做了许多工作的。如果说使用编程式事务处理,过程其实比较清楚,我们可以参考书中的例子:
  

Java代码 

599 TransactionDefinition td = new DefaultTransactionDefinition();   

600 TransactionStatus status = transactionManager.getTransaction(td);   

601 try{   

602       ……//这里是我们的业务方法  

603 }catch (ApplicationException e) {   

604    transactionManager.rollback(status);   

605    throw e   

606 }   

607 transactionManager.commit(status);   

608  ……..  

609 TransactionDefinition td = new DefaultTransactionDefinition();  

610 TransactionStatus status = transactionManager.getTransaction(td);  

611 try{  

612       ......//这里是我们的业务方法  

613 }catch (ApplicationException e) {  

614    transactionManager.rollback(status);  

615    throw e  

616 }  

617 <a href="http://transactionManager.com" title="http://transactionManager.com" target="_blank">transactionManager.com</a>mit(status);  

618  ........  

我们看到这里选取了默认的事务配置DefaultTransactionDefinition,同时在创建事物的过程中得到TransactionStatus,然后通过直接调用事务管理器的相关方法就能完成事务处理。
 声明式事务处理也同样实现了类似的过程,只是因为采用了声明的方法,需要增加对属性的读取处理,并且需要把整个过程整合到Spring AOP框架中和IoC容器中去的过程。
 下面我们选取一个具体的transactionManager – DataSourceTransactionManager来看看其中事务处理的实现:
 同样的通过使用AbstractPlatformTransactionManager使用模板方法,这些都体现了对具体平台相关的事务管理器操作的封装,比如commit
  

Java代码 

619 public final void commit(TransactionStatus status) throws TransactionException {   

620     ……   

621     DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;   

622     if (defStatus.isLocalRollbackOnly()) {   

623         ……   

624         processRollback(defStatus);   

625         return;   

626     }   

627          …….   

628         processRollback(defStatus);   

629     ……   

630     }   

631   

632     processCommit(defStatus);   

633 }  

634 public final void commit(TransactionStatus status) throws TransactionException {  

635     ......  

636     DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;  

637     if (defStatus.isLocalRollbackOnly()) {  

638         ......  

639         processRollback(defStatus);  

640         return;  

641     }  

642          .......  

643         processRollback(defStatus);  

644     ......  

645     }  

646   

647     processCommit(defStatus);  

648 }  

通过对TransactionStatus的具体状态的判断,来决定具体的事务处理:
  

Java代码 

649 private void processCommit(DefaultTransactionStatus status) throws TransactionException {   

650     try {   

651         boolean beforeCompletionInvoked = false;   

652         try {   

653             triggerBeforeCommit(status);   

654             triggerBeforeCompletion(status);   

655             beforeCompletionInvoked = true;   

656             boolean globalRollbackOnly = false;   

657             if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {   

658                 globalRollbackOnly = status.isGlobalRollbackOnly();   

659             }   

660             if (status.hasSavepoint()) {   

661             ……..   

662                status.releaseHeldSavepoint();   

663             }   

664             else if (status.isNewTransaction()) {   

665             ……   

666                 doCommit(status);   

667             }   

668         ………   

669 }  

670 private void processCommit(DefaultTransactionStatus status) throws TransactionException {  

671     try {  

672         boolean beforeCompletionInvoked = false;  

673         try {  

674             triggerBeforeCommit(status);  

675             triggerBeforeCompletion(status);  

676             beforeCompletionInvoked = true;  

677             boolean globalRollbackOnly = false;  

678             if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {  

679                 globalRollbackOnly = status.isGlobalRollbackOnly();  

680             }  

681             if (status.hasSavepoint()) {  

682             ........  

683                status.releaseHeldSavepoint();  

684             }  

685             else if (status.isNewTransaction()) {  

686             ......  

687                 doCommit(status);  

688             }  

689         .........  

690 }  

这些模板方法的实现由具体的transactionManager来实现,比如在DataSourceTransactionManager:
  

Java代码 

691 protected void doCommit(DefaultTransactionStatus status) {   

692     //这里得到存在TransactionInfo中已经创建好的事务  

693     DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();   

694   

695     //这里得到和事务绑定的数据库连接  

696     Connection con = txObject.getConnectionHolder().getConnection();   

697     ……..   

698     try {   

699     //这里通过数据库连接来提交事务  

700         con.commit();   

701     }   

702    …….   

703 }   

704   

705 protected void doRollback(DefaultTransactionStatus status) {   

706     DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();   

707     Connection con = txObject.getConnectionHolder().getConnection();   

708     if (status.isDebug()) {   

709         logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");   

710     }   

711     try {   

712     //这里通过数据库连接来回滚事务  

713         con.rollback();   

714     }   

715     catch (SQLException ex) {   

716         throw new TransactionSystemException("Could not roll back JDBC transaction", ex);   

717     }   

718 }  

719 protected void doCommit(DefaultTransactionStatus status) {  

720     //这里得到存在TransactionInfo中已经创建好的事务  

721     DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();  

722   

723     //这里得到和事务绑定的数据库连接  

724     Connection con = txObject.getConnectionHolder().getConnection();  

725     ........  

726     try {  

727     //这里通过数据库连接来提交事务  

728         <a href="http://con.com" title="http://con.com" target="_blank">con.com</a>mit();  

729     }  

730    .......  

731 }  

732   

733 protected void doRollback(DefaultTransactionStatus status) {  

734     DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();  

735     Connection con = txObject.getConnectionHolder().getConnection();  

736     if (status.isDebug()) {  

737         logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");  

738     }  

739     try {  

740     //这里通过数据库连接来回滚事务  

741         con.rollback();  

742     }  

743     catch (SQLException ex) {  

744         throw new TransactionSystemException("Could not roll back JDBC transaction", ex);  

745     }  

746 }  

我们看到在DataSourceTransactionManager中最后还是交给connection来实现事务的提交和rollback。整个声明 式事务处理是事务处理在Spring AOP中的应用,我们看到了一个很好的使用Spring AOP的例子,在Spring声明式事务处理的源代码中我们可以看到:
 1.怎样封装各种不同平台下的事务处理代码
 2.怎样读取属性值和结合事务处理代码来完成既定的事务处理策略
 3.怎样灵活的使用SpringAOP框架。
 如果能够结合前面的Spring AOP的源代码来学习,理解可能会更深刻些。

 

前面我们分析了Spring AOP实现中得到Proxy对象的过程,下面我们看看在Spring AOP中拦截器链是怎样被调用的,也就是Proxy模式是怎样起作用的,或者说Spring是怎样为我们提供AOP功能的;
 在JdkDynamicAopProxy中生成Proxy对象的时候:
  

Java代码 

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);  

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);  

这里的this参数对应的是InvocationHandler对象,这里我们的JdkDynamicAopProxy实现了这个接口,也就是说当 Proxy对象的函数被调用的时候,这个InvocationHandlerinvoke方法会被作为回调函数调用,下面我们看看这个方法的实现:
  

Java代码 

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {   

    MethodInvocation invocation = null;   

    Object oldProxy = null;   

    boolean setProxyContext = false;   

  

    TargetSource targetSource = this.advised.targetSource;   

    Class targetClass = null;   

10     Object target = null;   

11   

12     try {   

13         // Try special rules for equals() method and implementation of the  

14         // Advised AOP configuration interface.  

15   

16         if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {   

17             // What if equals throws exception!?  

18             // This class implements the equals(Object) method itself.  

19             return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE;   

20         }   

21         if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {   

22             // This class implements the hashCode() method itself.  

23             return new Integer(hashCode());   

24         }   

25         if (Advised.class == method.getDeclaringClass()) {   

26             // service invocations on ProxyConfig with the proxy config  

27             return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);   

28         }   

29   

30         Object retVal = null;   

31   

32         if (this.advised.exposeProxy) {   

33             // make invocation available if necessary  

34             oldProxy = AopContext.setCurrentProxy(proxy);   

35             setProxyContext = true;   

36         }   

37   

38         // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,  

39         // in case it comes from a pool.  

40         // 这里是得到目标对象的地方,当然这个目标对象可能来自于一个实例池或者是一个简单的JAVA对象  

41         target = targetSource.getTarget();   

42         if (target != null) {   

43             targetClass = target.getClass();   

44         }   

45   

46         // get the interception chain for this method  

47         // 这里获得定义好的拦截器链  

48         List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(   

49                 this.advised, proxy, method, targetClass);   

50   

51         // Check whether we have any advice. If we don't, we can fallback on direct  

52         // reflective invocation of the target, and avoid creating a MethodInvocation.  

53         // 如果没有设定拦截器,那么我们就直接调用目标的对应方法  

54         if (chain.isEmpty()) {   

55             // We can skip creating a MethodInvocation: just invoke the target directly  

56             // Note that the final invoker must be an InvokerInterceptor so we know it does  

57             // nothing but a reflective operation on the target, and no hot swapping or fancy proxying  

58             retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);   

59         }   

60         else {   

61             // We need to create a method invocation…  

62             // invocation = advised.getMethodInvocationFactory().getMethodInvocation(  

63             //         proxy, method, targetClass, target, args, chain, advised);  

64             // 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法  

65             // 这里通过构造一个ReflectiveMethodInvocation来实现,下面我们会看这个ReflectiveMethodInvocation  

66             invocation = new ReflectiveMethodInvocation(   

67                     proxy, target, method, args, targetClass, chain);   

68   

69             // proceed to the joinpoint through the interceptor chain  

70             // 这里通过ReflectiveMethodInvocation来调用拦截器链和相应的目标方法  

71             retVal = invocation.proceed();   

72         }   

73   

74         // massage return value if necessary  

75         if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy)) {   

76             // Special case: it returned "this" and the return type of the method is type-compatible  

77             // Note that we can't help if the target sets  

78             // a reference to itself in another returned object.  

79             retVal = proxy;   

80         }   

81         return retVal;   

82     }   

83     finally {   

84         if (target != null && !targetSource.isStatic()) {   

85             // must have come from TargetSource  

86             targetSource.releaseTarget(target);   

87         }   

88   

89         if (setProxyContext) {   

90             // restore old proxy  

91             AopContext.setCurrentProxy(oldProxy);   

92         }   

93     }   

94 }  

95 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  

96     MethodInvocation invocation = null;  

97     Object oldProxy = null;  

98     boolean setProxyContext = false;  

99   

100     TargetSource targetSource = this.advised.targetSource;  

101     Class targetClass = null;  

102     Object target = null;  

103   

104     try {  

105         // Try special rules for equals() method and implementation of the  

106         // Advised AOP configuration interface.  

107   

108         if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {  

109             // What if equals throws exception!?  

110             // This class implements the equals(Object) method itself.  

111             return equals(args[0]) ? Boolean.TRUE : Boolean.FALSE;  

112         }  

113         if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {  

114             // This class implements the hashCode() method itself.  

115             return new Integer(hashCode());  

116         }  

117         if (Advised.class == method.getDeclaringClass()) {  

118             // service invocations on ProxyConfig with the proxy config  

119             return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);  

120         }  

121   

122         Object retVal = null;  

123   

124         if (this.advised.exposeProxy) {  

125             // make invocation available if necessary  

126             oldProxy = AopContext.setCurrentProxy(proxy);  

127             setProxyContext = true;  

128         }  

129   

130         // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,  

131         // in case it comes from a pool.  

132         // 这里是得到目标对象的地方,当然这个目标对象可能来自于一个实例池或者是一个简单的JAVA对象  

133         target = targetSource.getTarget();  

134         if (target != null) {  

135             targetClass = target.getClass();  

136         }  

137   

138         // get the interception chain for this method  

139         // 这里获得定义好的拦截器链  

140         List chain = this.advised.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(  

141                 this.advised, proxy, method, targetClass);  

142   

143         // Check whether we have any advice. If we don't, we can fallback on direct  

144         // reflective invocation of the target, and avoid creating a MethodInvocation.  

145         // 如果没有设定拦截器,那么我们就直接调用目标的对应方法  

146         if (chain.isEmpty()) {  

147             // We can skip creating a MethodInvocation: just invoke the target directly  

148             // Note that the final invoker must be an InvokerInterceptor so we know it does  

149             // nothing but a reflective operation on the target, and no hot swapping or fancy proxying  

150             retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);  

151         }  

152         else {  

153             // We need to create a method invocation...  

154             // invocation = advised.getMethodInvocationFactory().getMethodInvocation(  

155             //         proxy, method, targetClass, target, args, chain, advised);  

156             // 如果有拦截器的设定,那么需要调用拦截器之后才调用目标对象的相应方法  

157             // 这里通过构造一个ReflectiveMethodInvocation来实现,下面我们会看这个ReflectiveMethodInvocation类  

158             invocation = new ReflectiveMethodInvocation(  

159                     proxy, target, method, args, targetClass, chain);  

160   

161             // proceed to the joinpoint through the interceptor chain  

162             // 这里通过ReflectiveMethodInvocation来调用拦截器链和相应的目标方法  

163             retVal = invocation.proceed();  

164         }  

165   

166         // massage return value if necessary  

167         if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy)) {  

168             // Special case: it returned "this" and the return type of the method is type-compatible  

169             // Note that we can't help if the target sets  

170             // a reference to itself in another returned object.  

171             retVal = proxy;  

172         }  

173         return retVal;  

174     }  

175     finally {  

176         if (target != null && !targetSource.isStatic()) {  

177             // must have come from TargetSource  

178             targetSource.releaseTarget(target);  

179         }  

180   

181         if (setProxyContext) {  

182             // restore old proxy  

183             AopContext.setCurrentProxy(oldProxy);  

184         }  

185     }  

186 }  

我们先看看目标对象方法的调用,这里是通过AopUtils的方法调用 – 使用反射机制来对目标对象的方法进行调用:
  

Java代码 

187 public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)   

188     throws Throwable {   

189   

190     // Use reflection to invoke the method.  

191     // 利用放射机制得到相应的方法,并且调用invoke  

192     try {   

193         if (!Modifier.isPublic(method.getModifiers()) ||   

194                 !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {   

195             method.setAccessible(true);   

196         }   

197         return method.invoke(target, args);   

198     }   

199     catch (InvocationTargetException ex) {   

200         // Invoked method threw a checked exception.  

201         // We must rethrow it. The client won't see the interceptor.  

202         throw ex.getTargetException();   

203     }   

204     catch (IllegalArgumentException ex) {   

205         throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +   

206                 method + "] on target [" + target + "]", ex);   

207     }   

208     catch (IllegalAccessException ex) {   

209         throw new AopInvocationException("Couldn't access method: " + method, ex);   

210     }   

211 }  

212 public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)  

213     throws Throwable {  

214   

215     // Use reflection to invoke the method.  

216     // 利用放射机制得到相应的方法,并且调用invoke  

217     try {  

218         if (!Modifier.isPublic(method.getModifiers()) ||  

219                 !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {  

220             method.setAccessible(true);  

221         }  

222         return method.invoke(target, args);  

223     }  

224     catch (InvocationTargetException ex) {  

225         // Invoked method threw a checked exception.  

226         // We must rethrow it. The client won't see the interceptor.  

227         throw ex.getTargetException();  

228     }  

229     catch (IllegalArgumentException ex) {  

230         throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +  

231                 method + "] on target [" + target + "]", ex);  

232     }  

233     catch (IllegalAccessException ex) {  

234         throw new AopInvocationException("Couldn't access method: " + method, ex);  

235     }  

236 }  

对拦截器链的调用处理是在ReflectiveMethodInvocation里实现的:
  

Java代码 

237 public Object proceed() throws Throwable {   

238     //    We start with an index of -1 and increment early.  

239     // 这里直接调用目标对象的方法,没有拦截器的调用或者拦截器已经调用完了,这个currentInterceptorIndex的初始值是0  

240     if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) {   

241         return invokeJoinpoint();   

242     }   

243   

244     Object interceptorOrInterceptionAdvice =   

245         this.interceptorsAndDynamicMethodMatchers.get(this.currentInterceptorIndex);   

246     if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {   

247         // Evaluate dynamic method matcher here: static part will already have  

248         // been evaluated and found to match.  

249         // 这里获得相应的拦截器,如果拦截器可以匹配的上的话,那就调用拦截器的invoke方法  

250         InterceptorAndDynamicMethodMatcher dm =   

251             (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;   

252         if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {   

253             return dm.interceptor.invoke(nextInvocation());   

254         }   

255         else {   

256             // Dynamic matching failed.  

257             // Skip this interceptor and invoke the next in the chain.  

258             // 如果拦截器匹配不上,那就调用下一个拦截器,这个时候拦截器链的位置指示后移并迭代调用当前的proceed方法  

259             this.currentInterceptorIndex++;   

260             return proceed();   

261         }   

262     }   

263     else {   

264         // It's an interceptor, so we just invoke it: The pointcut will have  

265         // been evaluated statically before this object was constructed.  

266         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(nextInvocation());   

267     }   

268 }  

269 public Object proceed() throws Throwable {  

270     //    We start with an index of -1 and increment early.  

271     // 这里直接调用目标对象的方法,没有拦截器的调用或者拦截器已经调用完了,这个currentInterceptorIndex的初始值是0  

272     if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()) {  

273         return invokeJoinpoint();  

274     }  

275   

276     Object interceptorOrInterceptionAdvice =  

277         this.interceptorsAndDynamicMethodMatchers.get(this.currentInterceptorIndex);  

278     if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  

279         // Evaluate dynamic method matcher here: static part will already have  

280         // been evaluated and found to match.  

281         // 这里获得相应的拦截器,如果拦截器可以匹配的上的话,那就调用拦截器的invoke方法  

282         InterceptorAndDynamicMethodMatcher dm =  

283             (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  

284         if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  

285             return dm.interceptor.invoke(nextInvocation());  

286         }  

287         else {  

288             // Dynamic matching failed.  

289             // Skip this interceptor and invoke the next in the chain.  

290             // 如果拦截器匹配不上,那就调用下一个拦截器,这个时候拦截器链的位置指示后移并迭代调用当前的proceed方法  

291             this.currentInterceptorIndex++;  

292             return proceed();  

293         }  

294     }  

295     else {  

296         // It's an interceptor, so we just invoke it: The pointcut will have  

297         // been evaluated statically before this object was constructed.  

298         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(nextInvocation());  

299     }  

300 }  

这里把当前的拦截器链以及在拦截器链的位置标志都clone到一个MethodInvocation对象了,作用是当前的拦截器执行完之后,会继续沿着得到这个拦截器链执行下面的拦截行为,也就是会迭代的调用上面这个proceed:
  

Java代码 

301 private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException {   

302     ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone();   

303     invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1;   

304     invocation.parent = this;   

305     return invocation;   

306 }  

307 private ReflectiveMethodInvocation nextInvocation() throws CloneNotSupportedException {  

308     ReflectiveMethodInvocation invocation = (ReflectiveMethodInvocation) clone();  

309     invocation.currentInterceptorIndex = this.currentInterceptorIndex + 1;  

310     invocation.parent = this;  

311     return invocation;  

312 }  

这里的nextInvocation就已经包含了当前的拦截链的基本信息,我们看到在Interceptor中的实现比如TransactionInterceptor的实现中:
  

Java代码 

313 public Object invoke(final MethodInvocation invocation) throws Throwable {   

314    ……//这里是TransactionInterceptor插入的事务处理代码,我们会在后面分析事务处理实现的时候进行分析  

315         try {   

316             //这里是对配置的拦截器链进行迭代处理的调用  

317             retVal = invocation.proceed();   

318         }   

319    ……//省略了和事务处理的异常处理代码 ,也是TransactionInterceptor插入的处理  

320       else {   

321         try {   

322             Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,   

323                     new TransactionCallback() {   

324                         public Object doInTransaction(TransactionStatus status) {   

325                              //这里是TransactionInterceptor插入对事务处理的代码  

326                             TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);   

327                             //这里是对配置的拦截器链进行迭代处理的调用,接着顺着拦截器进行处理  

328                             try {                           

329                                 return invocation.proceed();   

330                             }   

331    ……//省略了和事务处理的异常处理代码 ,也是TransactionInterceptor插入的处理  

332    }  

333 public Object invoke(final MethodInvocation invocation) throws Throwable {  

334    ......//这里是TransactionInterceptor插入的事务处理代码,我们会在后面分析事务处理实现的时候进行分析  

335         try {  

336             //这里是对配置的拦截器链进行迭代处理的调用  

337             retVal = invocation.proceed();  

338         }  

339    ......//省略了和事务处理的异常处理代码 ,也是TransactionInterceptor插入的处理  

340       else {  

341         try {  

342             Object result = ((CallbackPreferringPlatformTransactionManager) getTransactionManager()).execute(txAttr,  

343                     new TransactionCallback() {  

344                         public Object doInTransaction(TransactionStatus status) {  

345                              //这里是TransactionInterceptor插入对事务处理的代码  

346                             TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointIdentification, status);  

347                             //这里是对配置的拦截器链进行迭代处理的调用,接着顺着拦截器进行处理  

348                             try {  

349                                 return invocation.proceed();  

350                             }  

351    ......//省略了和事务处理的异常处理代码 ,也是TransactionInterceptor插入的处理  

352    }  

从上面的分析我们看到了Spring AOP的基本实现,比如Spring怎样得到Proxy,怎样利用JAVA Proxy以及反射机制对用户定义的拦截器链进行处理。

 

O/R工具出现之后,简化了许多复杂的信息持久化的开发。Spring应用开发者可以通过Spring提供的O/R方案更方便的使用各种持久化工具,比如Hibernate;下面我们就Spring+Hibernate中的Spring实现做一个简单的剖析。
 SpringHinberanate的配置是通过LocalSessionFactoryBean来完成的,这是一个工厂Bean的实现,在基类AbstractSessionFactoryBean中:
  

Java代码 

/** 

 * 这是FactoryBean需要实现的接口方法,直接取得当前的sessionFactory的值 

 */  

public Object getObject() {   

    return this.sessionFactory;   

}  

/** 

 * 这是FactoryBean需要实现的接口方法,直接取得当前的sessionFactory的值 

 */  

10 public Object getObject() {  

11     return this.sessionFactory;  

12 }  

这个值在afterPropertySet中定义:
  

Java代码 

13 public void afterPropertiesSet() throws Exception {   

14     //这个buildSessionFactory是通过配置信息得到SessionFactory的地方  

15     SessionFactory rawSf = buildSessionFactory();   

16     //这里使用了Proxy方法插入对getCurrentSession的拦截,得到和事务相关的session  

17     this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);   

18 }  

19 public void afterPropertiesSet() throws Exception {  

20     //这个buildSessionFactory是通过配置信息得到SessionFactory的地方  

21     SessionFactory rawSf = buildSessionFactory();  

22     //这里使用了Proxy方法插入对getCurrentSession的拦截,得到和事务相关的session  

23     this.sessionFactory = wrapSessionFactoryIfNecessary(rawSf);  

24 }  

我们先看看SessionFactory是怎样创建的,这个方法很长,包含了创建HibernateSessionFactory的详尽步骤:
  

Java代码 

25 protected SessionFactory buildSessionFactory() throws Exception {   

26     SessionFactory sf = null;   

27   

28     // Create Configuration instance.  

29     Configuration config = newConfiguration();   

30   

31     //这里配置数据源,事务管理器,LobHanderHolder中,这个Holder是一个ThreadLocal变量,这样这些资源就和线程绑定了  

32     if (this.dataSource != null) {   

33         // Make given DataSource available for SessionFactory configuration.  

34         configTimeDataSourceHolder.set(this.dataSource);   

35     }   

36   

37     if (this.jtaTransactionManager != null) {   

38         // Make Spring-provided JTA TransactionManager available.  

39         configTimeTransactionManagerHolder.set(this.jtaTransactionManager);   

40     }   

41   

42     if (this.lobHandler != null) {   

43         // Make given LobHandler available for SessionFactory configuration.  

44         // Do early because because mapping resource might refer to custom types.  

45         configTimeLobHandlerHolder.set(this.lobHandler);   

46     }   

47   

48     //这里是使用Hibernate的各个属性的配置,这里使用了Configuration类来抽象这些数据  

49     try {   

50         // Set connection release mode "on_close" as default.  

51         // This was the case for Hibernate 3.0; Hibernate 3.1 changed  

52         // it to "auto" (i.e. "after_statement" or "after_transaction").  

53         // However, for Spring's resource management (in particular for  

54         // HibernateTransactionManager), "on_close" is the better default.  

55         config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());   

56   

57         if (!isExposeTransactionAwareSessionFactory()) {   

58             // Not exposing a SessionFactory proxy with transaction-aware  

59             // getCurrentSession() method -> set Hibernate 3.1 CurrentSessionContext  

60             // implementation instead, providing the Spring-managed Session that way.  

61             // Can be overridden by a custom value for corresponding Hibernate property.  

62             config.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS,   

63                     "org.springframework.orm.hibernate3.SpringSessionContext");   

64         }   

65   

66         if (this.entityInterceptor != null) {   

67             // Set given entity interceptor at SessionFactory level.  

68             config.setInterceptor(this.entityInterceptor);   

69         }   

70   

71         if (this.namingStrategy != null) {   

72             // Pass given naming strategy to Hibernate Configuration.  

73             config.setNamingStrategy(this.namingStrategy);   

74         }   

75   

76         if (this.typeDefinitions != null) {   

77             // Register specified Hibernate type definitions.  

78             Mappings mappings = config.createMappings();   

79             for (int i = 0; i < this.typeDefinitions.length; i++) {   

80                 TypeDefinitionBean typeDef = this.typeDefinitions[i];   

81                 mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());   

82             }   

83         }   

84   

85         if (this.filterDefinitions != null) {   

86             // Register specified Hibernate FilterDefinitions.  

87             for (int i = 0; i < this.filterDefinitions.length; i++) {   

88                 config.addFilterDefinition(this.filterDefinitions[i]);   

89             }   

90         }   

91   

92         if (this.configLocations != null) {   

93             for (int i = 0; i < this.configLocations.length; i++) {   

94                 // Load Hibernate configuration from given location.  

95                 config.configure(this.configLocations[i].getURL());   

96             }   

97         }   

98   

99         if (this.hibernateProperties != null) {   

100             // Add given Hibernate properties to Configuration.  

101             config.addProperties(this.hibernateProperties);   

102         }   

103   

104         if (this.dataSource != null) {   

105             boolean actuallyTransactionAware =   

106                     (this.useTransactionAwareDataSource || this.dataSource instanceof TransactionAwareDataSourceProxy);   

107             // Set Spring-provided DataSource as Hibernate ConnectionProvider.  

108             config.setProperty(Environment.CONNECTION_PROVIDER,   

109                     actuallyTransactionAware ?   

110                     TransactionAwareDataSourceConnectionProvider.class.getName() :   

111                     LocalDataSourceConnectionProvider.class.getName());   

112         }   

113   

114         if (this.jtaTransactionManager != null) {   

115             // Set Spring-provided JTA TransactionManager as Hibernate property.  

116             config.setProperty(   

117                     Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());   

118         }   

119   

120         if (this.mappingLocations != null) {   

121             // Register given Hibernate mapping definitions, contained in resource files.  

122             for (int i = 0; i < this.mappingLocations.length; i++) {   

123                 config.addInputStream(this.mappingLocations[i].getInputStream());   

124             }   

125         }   

126   

127         if (this.cacheableMappingLocations != null) {   

128             // Register given cacheable Hibernate mapping definitions, read from the file system.  

129             for (int i = 0; i < this.cacheableMappingLocations.length; i++) {   

130                 config.addCacheableFile(this.cacheableMappingLocations[i].getFile());   

131             }   

132         }   

133   

134         if (this.mappingJarLocations != null) {   

135             // Register given Hibernate mapping definitions, contained in jar files.  

136             for (int i = 0; i < this.mappingJarLocations.length; i++) {   

137                 Resource resource = this.mappingJarLocations[i];   

138                 config.addJar(resource.getFile());   

139             }   

140         }   

141   

142         if (this.mappingDirectoryLocations != null) {   

143             // Register all Hibernate mapping definitions in the given directories.  

144             for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {   

145                 File file = this.mappingDirectoryLocations[i].getFile();   

146                 if (!file.isDirectory()) {   

147                     throw new IllegalArgumentException(   

148                             "Mapping directory location [" + this.mappingDirectoryLocations[i] +   

149                             "] does not denote a directory");   

150                 }   

151                 config.addDirectory(file);   

152             }   

153         }   

154   

155         if (this.entityCacheStrategies != null) {   

156             // Register cache strategies for mapped entities.  

157             for (Enumeration classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {   

158                 String className = (String) classNames.nextElement();   

159                 String[] strategyAndRegion =   

160                         StringUtils.commaDelimitedListToStringArray(this.entityCacheStrategies.getProperty(className));   

161                 if (strategyAndRegion.length > 1) {   

162                     config.setCacheConcurrencyStrategy(className, strategyAndRegion[0], strategyAndRegion[1]);   

163                 }   

164                 else if (strategyAndRegion.length > 0) {   

165                     config.setCacheConcurrencyStrategy(className, strategyAndRegion[0]);   

166                 }   

167             }   

168         }   

169   

170         if (this.collectionCacheStrategies != null) {   

171             // Register cache strategies for mapped collections.  

172             for (Enumeration collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {   

173                 String collRole = (String) collRoles.nextElement();   

174                 String[] strategyAndRegion =   

175                         StringUtils.commaDelimitedListToStringArray(this.collectionCacheStrategies.getProperty(collRole));   

176                 if (strategyAndRegion.length > 1) {   

177                     config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]);   

178                 }   

179                 else if (strategyAndRegion.length > 0) {   

180                     config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]);   

181                 }   

182             }   

183         }   

184   

185         if (this.eventListeners != null) {   

186             // Register specified Hibernate event listeners.  

187             for (Iterator it = this.eventListeners.entrySet().iterator(); it.hasNext();) {   

188                 Map.Entry entry = (Map.Entry) it.next();   

189                 Assert.isTrue(entry.getKey() instanceof String, "Event listener key needs to be of type String");   

190                 String listenerType = (String) entry.getKey();   

191                 Object listenerObject = entry.getValue();   

192                 if (listenerObject instanceof Collection) {   

193                     Collection listeners = (Collection) listenerObject;   

194                     EventListeners listenerRegistry = config.getEventListeners();   

195                     Object[] listenerArray =   

196                             (Object[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size());   

197                     listenerArray = listeners.toArray(listenerArray);   

198                     config.setListeners(listenerType, listenerArray);   

199                 }   

200                 else {   

201                     config.setListener(listenerType, listenerObject);   

202                 }   

203             }   

204         }   

205   

206         // Perform custom post-processing in subclasses.  

207         postProcessConfiguration(config);   

208   

209         // 这里是根据Configuration配置创建SessionFactory的地方  

210         logger.info("Building new Hibernate SessionFactory");   

211         this.configuration = config;   

212         sf = newSessionFactory(config);   

213     }   

214     //最后把和线程绑定的资源清空  

215     finally {   

216         if (this.dataSource != null) {   

217             // Reset DataSource holder.  

218             configTimeDataSourceHolder.set(null);   

219         }   

220   

221         if (this.jtaTransactionManager != null) {   

222             // Reset TransactionManager holder.  

223             configTimeTransactionManagerHolder.set(null);   

224         }   

225   

226         if (this.lobHandler != null) {   

227             // Reset LobHandler holder.  

228             configTimeLobHandlerHolder.set(null);   

229         }   

230     }   

231   

232     // Execute schema update if requested.  

233     if (this.schemaUpdate) {   

234         updateDatabaseSchema();   

235     }   

236   

237     return sf;   

238 }  

而直接调用org.hibernate.cfg.Configuration来得到需要的SessionFactory:
  

Java代码 

239 protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {   

240     return config.buildSessionFactory();   

241 }  

所以我们这里看到LocalSessionFactory大致起到的一个读取资源配置然后生成SessionFactory的作用;当然这里在得到 SessionFactory之后,还需要对session的事务管理作一些处理 – 使用了一个Proxy模式对getCurrentSession方法进行了拦截;
  

Java代码 

242 //这里先根据当前的SessionFactory的类型得到Proxy,然后插入Spring定义好的getCurrentSession拦截器  

243     protected SessionFactory getTransactionAwareSessionFactoryProxy(SessionFactory target) {   

244         Class sfInterface = SessionFactory.class;   

245         if (target instanceof SessionFactoryImplementor) {   

246             sfInterface = SessionFactoryImplementor.class;   

247         }   

248         return (SessionFactory) Proxy.newProxyInstance(sfInterface.getClassLoader(),   

249                 new Class[] {sfInterface}, new TransactionAwareInvocationHandler(target));   

250     }  

拦截器的实现如下:
  

Java代码 

251 private static class TransactionAwareInvocationHandler implements InvocationHandler {   

252   

253     private final SessionFactory target;   

254   

255     public TransactionAwareInvocationHandler(SessionFactory target) {   

256         this.target = target;   

257     }   

258   

259     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {   

260         // Invocation on SessionFactory/SessionFactoryImplementor interface coming in…  

261         // 这里对getCurrentSession方法进行拦截,得到一个和当前事务绑定的session交给用户  

262         if (method.getName().equals("getCurrentSession")) {   

263             // Handle getCurrentSession method: return transactional Session, if any.  

264             try {   

265                 return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);   

266             }   

267             catch (IllegalStateException ex) {   

268                 throw new HibernateException(ex.getMessage());   

269             }   

270         }   

271         else if (method.getName().equals("equals")) {   

272             // Only consider equal when proxies are identical.  

273             return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);   

274         }   

275         else if (method.getName().equals("hashCode")) {   

276             // Use hashCode of SessionFactory proxy.  

277             return new Integer(hashCode());   

278         }   

279   

280         // 这里是需要运行的SessionFactory的目标方法  

281         try {   

282             return method.invoke(this.target, args);   

283         }   

284         catch (InvocationTargetException ex) {   

285             throw ex.getTargetException();   

286         }   

287     }   

288 }  

我们看看getCurrentSession的实现,在SessionFactoryUtils中:
  

Java代码 

289 private static Session doGetSession(   

290             SessionFactory sessionFactory, Interceptor entityInterceptor,   

291             SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)   

292             throws HibernateException, IllegalStateException {   

293   

294         Assert.notNull(sessionFactory, "No SessionFactory specified");   

295   

296         //这个TransactionSynchronizationManagerResource是一个ThreadLocal变量,sessionFactory是一个单例,但ThreadLocal是和线程绑定的  

297         //这样就实现了Hiberante中常用的通过ThreadLocalsession管理机制  

298         SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);   

299         if (sessionHolder != null && !sessionHolder.isEmpty()) {   

300             // pre-bound Hibernate Session  

301             Session session = null;   

302             if (TransactionSynchronizationManager.isSynchronizationActive() &&   

303                     sessionHolder.doesNotHoldNonDefaultSession()) {   

304                 // Spring transaction management is active ->  

305                 // register pre-bound Session with it for transactional flushing.  

306                 session = sessionHolder.getValidatedSession();   

307                 if (session != null && !sessionHolder.isSynchronizedWithTransaction()) {   

308                     logger.debug("Registering Spring transaction synchronization for existing Hibernate Session");   

309                     TransactionSynchronizationManager.registerSynchronization(   

310                             new SpringSessionSynchronization(sessionHolder, sessionFactory, jdbcExceptionTranslator, false));   

311                     sessionHolder.setSynchronizedWithTransaction(true);   

312                     // Switch to FlushMode.AUTO, as we have to assume a thread-bound Session  

313                     // with FlushMode.NEVER, which needs to allow flushing within the transaction.  

314                     FlushMode flushMode = session.getFlushMode();   

315                     if (flushMode.lessThan(FlushMode.COMMIT) &&   

316                             !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {   

317                         session.setFlushMode(FlushMode.AUTO);   

318                         sessionHolder.setPreviousFlushMode(flushMode);   

319                     }   

320                 }   

321             }   

322             else {   

323                 // No Spring transaction management active -> try JTA transaction synchronization.  

324                 session = getJtaSynchronizedSession(sessionHolder, sessionFactory, jdbcExceptionTranslator);   

325             }   

326             if (session != null) {   

327                 return session;   

328             }   

329         }   

330         //这里直接打开一个Session  

331         logger.debug("Opening Hibernate Session");   

332         Session session = (entityInterceptor != null ?   

333                 sessionFactory.openSession(entityInterceptor) : sessionFactory.openSession());   

334   

335         // Use same Session for further Hibernate actions within the transaction.  

336         // Thread object will get removed by synchronization at transaction completion.  

337         // 把 新打开的Session放到SessionHolder,然后放到ThreadLocal里面去和线程绑定起来,这个ThreadLocal是 在 TransactionSynchronizationManager中配置好的,可以根据sessionFactory来索取  

338         // 同时根据事务处理的状态来配置session的属性,比如把FlushMode设置为Never,同时把session和事务处理关联起来  

339         if (TransactionSynchronizationManager.isSynchronizationActive()) {   

340             // We're within a Spring-managed transaction, possibly from JtaTransactionManager.  

341             logger.debug("Registering Spring transaction synchronization for new Hibernate Session");   

342             SessionHolder holderToUse = sessionHolder;   

343             if (holderToUse == null) {   

344                 holderToUse = new SessionHolder(session);   

345             }   

346             else {   

347                 holderToUse.addSession(session);   

348             }   

349             if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {   

350                 session.setFlushMode(FlushMode.NEVER);   

351             }   

352             TransactionSynchronizationManager.registerSynchronization(   

353                     new SpringSessionSynchronization(holderToUse, sessionFactory, jdbcExceptionTranslator, true));   

354             holderToUse.setSynchronizedWithTransaction(true);   

355             if (holderToUse != sessionHolder) {   

356                 TransactionSynchronizationManager.bindResource(sessionFactory, holderToUse);   

357             }   

358         }   

359         else {   

360             // No Spring transaction management active -> try JTA transaction synchronization.  

361             registerJtaSynchronization(session, sessionFactory, jdbcExceptionTranslator, sessionHolder);   

362         }   

363   

364         // Check whether we are allowed to return the Session.  

365         if (!allowCreate && !isSessionTransactional(session, sessionFactory)) {   

366             closeSession(session);   

367             throw new IllegalStateException("No Hibernate Session bound to thread, " +   

368                 "and configuration does not allow creation of non-transactional one here");   

369         }   

370   

371         return session;   

372     }  

这里就是在Spring中为使用HiberanteSessionFactory以及Session做的准备工作,在这个基础上,用户可以通过使用 HibernateTemplate来使用HibernateO/R功能,和以前看到的一样这是一个execute的回调:
  

Java代码 

373 public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {   

374     Assert.notNull(action, "Callback object must not be null");   

375     //这里得到配置好的HibernateSession  

376     Session session = getSession();   

377     boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());   

378     if (existingTransaction) {   

379         logger.debug("Found thread-bound Session for HibernateTemplate");   

380     }   

381   

382     FlushMode previousFlushMode = null;   

383     try {   

384         previousFlushMode = applyFlushMode(session, existingTransaction);   

385         enableFilters(session);   

386         Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));   

387         //这里是回调的入口  

388         Object result = action.doInHibernate(sessionToExpose);   

389         flushIfNecessary(session, existingTransaction);   

390         return result;   

391     }   

392     catch (HibernateException ex) {   

393         throw convertHibernateAccessException(ex);   

394     }   

395     catch (SQLException ex) {   

396         throw convertJdbcAccessException(ex);   

397     }   

398     catch (RuntimeException ex) {   

399         // Callback code threw application exception…  

400         throw ex;   

401     }   

402     finally {   

403         //如果这个调用的方法在一个事务当中,  

404         if (existingTransaction) {   

405             logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");   

406             disableFilters(session);   

407             if (previousFlushMode != null) {   

408                 session.setFlushMode(previousFlushMode);   

409             }   

410         } //否则把Session关闭  

411         else {   

412             // Never use deferred close for an explicitly new Session.  

413             if (isAlwaysUseNewSession()) {   

414                 SessionFactoryUtils.closeSession(session);   

415             }   

416             else {   

417                 SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());   

418             }   

419         }   

420     }   

421 }  

我们看看怎样得到对应的Session的,仍然使用了SessionFactoryUtils的方法doGetSession:
  

Java代码 

422 protected Session getSession() {   

423     if (isAlwaysUseNewSession()) {   

424         return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());   

425     }   

426     else if (!isAllowCreate()) {   

427         return SessionFactoryUtils.getSession(getSessionFactory(), false);   

428     }   

429     else {   

430         return SessionFactoryUtils.getSession(   

431                 getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());   

432     }   

433 }  

 

简单分析一下Spring Acegi的源代码实现: 
 Servlet.Filter的实现AuthenticationProcessingFilter启动Web页面的验证过程 – AbstractProcessingFilter定义了整个验证过程的模板: 

Java代码 

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)  

    throws IOException, ServletException {  

    //这里检验是不是符合ServletRequest/SevletResponse的要求  

    if (!(request instanceof HttpServletRequest)) {  

        throw new ServletException("Can only process HttpServletRequest");  

    }  

  

    if (!(response instanceof HttpServletResponse)) {  

        throw new ServletException("Can only process HttpServletResponse");  

10     }  

11   

12     HttpServletRequest httpRequest = (HttpServletRequest) request;  

13     HttpServletResponse httpResponse = (HttpServletResponse) response;  

14     //根据HttpServletRequestHttpServletResponse来进行验证  

15     if (requiresAuthentication(httpRequest, httpResponse)) {  

16         if (logger.isDebugEnabled()) {  

17             logger.debug("Request is to process authentication");  

18         }  

19         //这里定义Acegi中的Authentication对象来持有相关的用户验证信息  

20         Authentication authResult;  

21   

22         try {  

23             onPreAuthentication(httpRequest, httpResponse);  

24             //这里的具体验证过程委托给子类完成,比如AuthenticationProcessingFilter来完成基于Web页面的用户验证  

25             authResult = attemptAuthentication(httpRequest);  

26         } catch (AuthenticationException failed) {  

27             // Authentication failed  

28             unsuccessfulAuthentication(httpRequest, httpResponse, failed);  

29   

30             return;  

31         }  

32   

33         // Authentication success  

34         if (continueChainBeforeSuccessfulAuthentication) {  

35             chain.doFilter(request, response);  

36         }  

37         //完成验证后的后续工作,比如跳转到相应的页面  

38         successfulAuthentication(httpRequest, httpResponse, authResult);  

39   

40         return;  

41     }  

42   

43     chain.doFilter(request, response);  

44 }  


 在AuthenticationProcessingFilter中的具体验证过程是这样的: 

Java代码 

45 public Authentication attemptAuthentication(HttpServletRequest request)  

46     throws AuthenticationException {  

47     //这里从HttpServletRequest中得到用户验证的用户名和密码  

48     String username = obtainUsername(request);  

49     String password = obtainPassword(request);  

50   

51     if (username == null) {  

52         username = "";  

53     }  

54   

55     if (password == null) {  

56         password = "";  

57     }  

58     //这里根据得到的用户名和密码去构造一个Authentication对象提供给AuthenticationManager进行验证,里面包含了用户的用户名和密码信息  

59     UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);  

60   

61     // Place the last username attempted into HttpSession for views  

62     request.getSession().setAttribute(ACEGI_SECURITY_LAST_USERNAME_KEY, username);  

63   

64     // Allow subclasses to set the "details" property  

65     setDetails(request, authRequest);  

66     //这里启动AuthenticationManager进行验证过程  

67     return this.getAuthenticationManager().authenticate(authRequest);  

68 }  


 在Acegi框架中,进行验证管理的主要类是AuthenticationManager,我们看看它是怎样进行验证管理的 – 验证的调用入口是authenticateAbstractAuthenticationManager的实现中: 
 //这是进行验证的函数,返回一个Authentication对象来记录验证的结果,其中包含了用户的验证信息,权限配置等,同时这个Authentication会以后被授权模块使用 

Java代码 

69 //如果验证失败,那么在验证过程中会直接抛出异常  

70     public final Authentication authenticate(Authentication authRequest)  

71         throws AuthenticationException {  

72         try {//这里是实际的验证处理,我们下面使用ProviderManager来说明具体的验证过程,传入的参数authRequest里面已经包含了从HttpServletRequest中得到的用户输入的用户名和密码  

73             Authentication authResult = doAuthentication(authRequest);  

74             copyDetails(authRequest, authResult);  

75   

76             return authResult;  

77         } catch (AuthenticationException e) {  

78             e.setAuthentication(authRequest);  

79             throw e;  

80         }  

81     }  


 在ProviderManager中进行实际的验证工作,假设这里使用数据库来存取用户信息: 

Java代码 

82 public Authentication doAuthentication(Authentication authentication)  

83     throws AuthenticationException {  

84     //这里取得配置好的provider链的迭代器,在配置的时候可以配置多个provider,这里我们配置的是DaoAuthenticationProvider来说明它使用数据库来保存用户的用户名和密码信息。  

85     Iterator iter = providers.iterator();  

86   

87     Class toTest = authentication.getClass();  

88   

89     AuthenticationException lastException = null;  

90   

91     while (iter.hasNext()) {  

92         AuthenticationProvider provider = (AuthenticationProvider) iter.next();  

93   

94         if (provider.supports(toTest)) {  

95             logger.debug("Authentication attempt using " + provider.getClass().getName());  

96             //这个result包含了验证中得到的结果信息  

97             Authentication result = null;  

98   

99             try {//这里是provider进行验证处理的过程  

100                 result = provider.authenticate(authentication);  

101                 sessionController.checkAuthenticationAllowed(result);  

102             } catch (AuthenticationException ae) {  

103                 lastException = ae;  

104                 result = null;  

105             }  

106   

107             if (result != null) {  

108                 sessionController.registerSuccessfulAuthentication(result);  

109                 publishEvent(new AuthenticationSuccessEvent(result));  

110   

111                 return result;  

112             }  

113         }  

114     }  

115   

116     if (lastException == null) {  

117         lastException = new ProviderNotFoundException(messages.getMessage("ProviderManager.providerNotFound",  

118                     new Object[] {toTest.getName()}, "No AuthenticationProvider found for {0}"));  

119     }  

120   

121     // 这里发布事件来通知上下文的监听器  

122     String className = exceptionMappings.getProperty(lastException.getClass().getName());  

123     AbstractAuthenticationEvent event = null;  

124   

125     if (className != null) {  

126         try {  

127             Class clazz = getClass().getClassLoader().loadClass(className);  

128             Constructor constructor = clazz.getConstructor(new Class[] {  

129                         Authentication.class, AuthenticationException.class  

130                     });  

131             Object obj = constructor.newInstance(new Object[] {authentication, lastException});  

132             Assert.isInstanceOf(AbstractAuthenticationEvent.class, obj, "Must be an AbstractAuthenticationEvent");  

133             event = (AbstractAuthenticationEvent) obj;  

134         } catch (ClassNotFoundException ignored) {}  

135         catch (NoSuchMethodException ignored) {}  

136         catch (IllegalAccessException ignored) {}  

137         catch (InstantiationException ignored) {}  

138         catch (InvocationTargetException ignored) {}  

139     }  

140   

141     if (event != null) {  

142         publishEvent(event);  

143     } else {  

144         if (logger.isDebugEnabled()) {  

145             logger.debug("No event was found for the exception " + lastException.getClass().getName());  

146         }  

147     }  

148   

149     // Throw the exception  

150     throw lastException;  

151 }  


 我们下面看看在DaoAuthenticationProvider是怎样从数据库中取出对应的验证信息进行用户验证的,在它的基类AbstractUserDetailsAuthenticationProvider定义了验证的处理模板: 

Java代码 

152 public Authentication authenticate(Authentication authentication)  

153     throws AuthenticationException {  

154     Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,  

155         messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",  

156             "Only UsernamePasswordAuthenticationToken is supported"));  

157   

158     // 这里取得用户输入的用户名  

159     String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();  

160     // 如果配置了缓存,从缓存中去取以前存入的用户验证信息 这里是UserDetail,是服务器端存在数据库里的用户信息,这样就不用每次都去数据库中取了  

161     boolean cacheWasUsed = true;  

162     UserDetails user = this.userCache.getUserFromCache(username);  

163     //没有取到,设置标志位,下面会把这次取到的服务器端用户信息存入缓存中去  

164     if (user == null) {  

165         cacheWasUsed = false;  

166   

167         try {//这里是调用UserDetailService去取用户数据库里信息的地方  

168             user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);  

169         } catch (UsernameNotFoundException notFound) {  

170             if (hideUserNotFoundExceptions) {  

171                 throw new BadCredentialsException(messages.getMessage(  

172                         "AbstractUserDetailsAuthenticationProvider.badCredentials""Bad credentials"));  

173             } else {  

174                 throw notFound;  

175             }  

176         }  

177   

178         Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");  

179     }  

180   

181     if (!user.isAccountNonLocked()) {  

182         throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",  

183                 "User account is locked"));  

184     }  

185   

186     if (!user.isEnabled()) {  

187         throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",  

188                 "User is disabled"));  

189     }  

190   

191     if (!user.isAccountNonExpired()) {  

192         throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",  

193                 "User account has expired"));  

194     }  

195   

196     // This check must come here, as we don't want to tell users  

197     // about account status unless they presented the correct credentials  

198     try {//这里是验证过程,在retrieveUser中从数据库中得到用户的信息,在additionalAuthenticationChecks中进行对比用户输入和服务器端的用户信息  

199           //如果验证通过,那么构造一个Authentication对象来让以后的授权使用,如果验证不通过,直接抛出异常结束鉴权过程  

200         additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);  

201     } catch (AuthenticationException exception) {  

202         if (cacheWasUsed) {  

203             // There was a problem, so try again after checking  

204             // we're using latest data (ie not from the cache)  

205             cacheWasUsed = false;  

206             user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);  

207             additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);  

208         } else {  

209             throw exception;  

210         }  

211     }  

212   

213     if (!user.isCredentialsNonExpired()) {  

214         throw new CredentialsExpiredException(messages.getMessage(  

215                 "AbstractUserDetailsAuthenticationProvider.credentialsExpired""User credentials have expired"));  

216     }  

217     //根据前面的缓存结果决定是不是要把当前的用户信息存入缓存以供下次验证使用  

218     if (!cacheWasUsed) {  

219         this.userCache.putUserInCache(user);  

220     }  

221   

222     Object principalToReturn = user;  

223   

224     if (forcePrincipalAsString) {  

225         principalToReturn = user.getUsername();  

226     }  

227     //最后返回Authentication记录了验证结果供以后的授权使用  

228     return createSuccessAuthentication(principalToReturn, authentication, user);  

229 }  

230 //这是是调用UserDetailService去加载服务器端用户信息的地方,从什么地方加载要看设置,这里我们假设由JdbcDaoImp来从数据中进行加载  

231 protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)  

232     throws AuthenticationException {  

233     UserDetails loadedUser;  

234     //这里调用UserDetailService去从数据库中加载用户验证信息,同时返回从数据库中返回的信息,这些信息放到了UserDetails对象中去了  

235     try {  

236         loadedUser = this.getUserDetailsService().loadUserByUsername(username);  

237     } catch (DataAccessException repositoryProblem) {  

238         throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);  

239     }  

240   

241     if (loadedUser == null) {  

242         throw new AuthenticationServiceException(  

243             "UserDetailsService returned null, which is an interface contract violation");  

244     }  

245     return loadedUser;  

246 }  


 下面我们重点分析一下JdbcDaoImp这个类来看看具体是怎样从数据库中得到用户信息的: 

Java代码 

247 public class JdbcDaoImpl extends JdbcDaoSupport implements UserDetailsService {  

248     //~ Static fields/initializers =====================================================================================  

249     //这里是预定义好的对查询语句,对应于默认的数据库表结构,也可以自己定义查询语句对应特定的用户数据库验证表的设计  

250     public static final String DEF_USERS_BY_USERNAME_QUERY =  

251             "SELECT username,password,enabled FROM users WHERE username = ?";  

252     public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =  

253             "SELECT username,authority FROM authorities WHERE username = ?";  

254   

255     //~ Instance fields ================================================================================================  

256     //这里使用Spring JDBC来进行数据库操作  

257     protected MappingSqlQuery authoritiesByUsernameMapping;  

258     protected MappingSqlQuery usersByUsernameMapping;  

259     private String authoritiesByUsernameQuery;  

260     private String rolePrefix = "";  

261     private String usersByUsernameQuery;  

262     private boolean usernameBasedPrimaryKey = true;  

263   

264     //~ Constructors ===================================================================================================  

265     //在初始化函数中把查询语句设置为预定义的SQL语句  

266     public JdbcDaoImpl() {  

267         usersByUsernameQuery = DEF_USERS_BY_USERNAME_QUERY;  

268         authoritiesByUsernameQuery = DEF_AUTHORITIES_BY_USERNAME_QUERY;  

269     }  

270   

271     //~ Methods ========================================================================================================  

272   

273     protected void addCustomAuthorities(String username, List authorities) {}  

274   

275     public String getAuthoritiesByUsernameQuery() {  

276         return authoritiesByUsernameQuery;  

277     }  

278   

279     public String getRolePrefix() {  

280         return rolePrefix;  

281     }  

282   

283     public String getUsersByUsernameQuery() {  

284         return usersByUsernameQuery;  

285     }  

286   

287     protected void initDao() throws ApplicationContextException {  

288         initMappingSqlQueries();  

289     }  

290   

291     /** 

292      * Extension point to allow other MappingSqlQuery objects to be substituted in a subclass 

293      */  

294     protected void initMappingSqlQueries() {  

295         this.usersByUsernameMapping = new UsersByUsernameMapping(getDataSource());  

296         this.authoritiesByUsernameMapping = new AuthoritiesByUsernameMapping(getDataSource());  

297     }  

298   

299     public boolean isUsernameBasedPrimaryKey() {  

300         return usernameBasedPrimaryKey;  

301     }  

302     //这里是取得数据库用户信息的具体过程  

303     public UserDetails loadUserByUsername(String username)  

304         throws UsernameNotFoundException, DataAccessException {  

305         //根据用户名在用户表中得到用户信息,包括用户名,密码和用户是否有效的信息  

306         List users = usersByUsernameMapping.execute(username);  

307   

308         if (users.size() == 0) {  

309             throw new UsernameNotFoundException("User not found");  

310         }  

311         //取集合中的第一个作为有效的用户对象  

312         UserDetails user = (UserDetails) users.get(0); // contains no GrantedAuthority[]  

313         //这里在权限表中去取得用户的权限信息,同样的返回一个权限集合对应于这个用户  

314         List dbAuths = authoritiesByUsernameMapping.execute(user.getUsername());  

315   

316         addCustomAuthorities(user.getUsername(), dbAuths);  

317   

318         if (dbAuths.size() == 0) {  

319             throw new UsernameNotFoundException("User has no GrantedAuthority");  

320         }  

321         //这里根据得到的权限集合来配置返回的User对象供以后使用  

322         GrantedAuthority[] arrayAuths = (GrantedAuthority[]) dbAuths.toArray(new GrantedAuthority[dbAuths.size()]);  

323   

324         String returnUsername = user.getUsername();  

325   

326         if (!usernameBasedPrimaryKey) {  

327             returnUsername = username;  

328         }  

329   

330         return new User(returnUsername, user.getPassword(), user.isEnabled(), truetruetrue, arrayAuths);  

331     }  

332   

333     public void setAuthoritiesByUsernameQuery(String queryString) {  

334         authoritiesByUsernameQuery = queryString;  

335     }  

336   

337     public void setRolePrefix(String rolePrefix) {  

338         this.rolePrefix = rolePrefix;  

339     }  

340   

341     public void setUsernameBasedPrimaryKey(boolean usernameBasedPrimaryKey) {  

342         this.usernameBasedPrimaryKey = usernameBasedPrimaryKey;  

343     }  

344   

345     public void setUsersByUsernameQuery(String usersByUsernameQueryString) {  

346         this.usersByUsernameQuery = usersByUsernameQueryString;  

347     }  

348   

349     //~ Inner Classes ==================================================================================================  

350   

351     /** 

352      * 这里是调用Spring JDBC的数据库操作,具体可以参考对JDBC的分析,这个类的作用是把数据库查询得到的记录集合转换为对象集合 一个很简单的O/R实现 

353      */  

354     protected class AuthoritiesByUsernameMapping extends MappingSqlQuery {  

355         protected AuthoritiesByUsernameMapping(DataSource ds) {  

356             super(ds, authoritiesByUsernameQuery);  

357             declareParameter(new SqlParameter(Types.VARCHAR));  

358             compile();  

359         }  

360   

361         protected Object mapRow(ResultSet rs, int rownum)  

362             throws SQLException {  

363             String roleName = rolePrefix + rs.getString(2);  

364             GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);  

365   

366             return authority;  

367         }  

368     }  

369   

370     /** 

371      * Query object to look up a user. 

372      */  

373     protected class UsersByUsernameMapping extends MappingSqlQuery {  

374         protected UsersByUsernameMapping(DataSource ds) {  

375             super(ds, usersByUsernameQuery);  

376             declareParameter(new SqlParameter(Types.VARCHAR));  

377             compile();  

378         }  

379   

380         protected Object mapRow(ResultSet rs, int rownum)  

381             throws SQLException {  

382             String username = rs.getString(1);  

383             String password = rs.getString(2);  

384             boolean enabled = rs.getBoolean(3);  

385             UserDetails user = new User(username, password, enabled, truetruetrue,  

386                     new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});  

387   

388             return user;  

389         }  

390     }  

391 }  


 从数据库中得到用户信息后,就是一个比对用户输入的信息和这个数据库用户信息的比对过程,这个比对过程在DaoAuthenticationProvider: 

Java代码 

392 //这个UserDetail是从数据库中查询到的,这个authentication是从用户输入中得到的  

393     protected void additionalAuthenticationChecks(UserDetails userDetails,  

394         UsernamePasswordAuthenticationToken authentication)  

395         throws AuthenticationException {  

396         Object salt = null;  

397   

398         if (this.saltSource != null) {  

399             salt = this.saltSource.getSalt(userDetails);  

400         }  

401         //如果用户没有输入密码,直接抛出异常  

402         if (authentication.getCredentials() == null) {  

403             throw new BadCredentialsException(messages.getMessage(  

404                     "AbstractUserDetailsAuthenticationProvider.badCredentials""Bad credentials"),  

405                     includeDetailsObject ? userDetails : null);  

406         }  

407         //这里取得用户输入的密码  

408         String presentedPassword = authentication.getCredentials() == null ? "" : authentication.getCredentials().toString();  

409         //这里判断用户输入的密码是不是和数据库里的密码相同,这里可以使用passwordEncoder来对数据库里的密码加解密  

410         // 如果不相同,抛出异常,如果相同则鉴权成功  

411         if (!passwordEncoder.isPasswordValid(  

412                 userDetails.getPassword(), presentedPassword, salt)) {  

413             throw new BadCredentialsException(messages.getMessage(  

414                     "AbstractUserDetailsAuthenticationProvider.badCredentials""Bad credentials"),  

415                     includeDetailsObject ? userDetails : null);  

416         }  

417     }  


 上面分析了整个Acegi进行验证的过程,从AuthenticationProcessingFilter中拦截Http请求得到用户输入的用户名和密 码,这些用户输入的验证信息会被放到Authentication对象中持有并传递给AuthenticatioManager来对比在服务端的用户信息 来完成整个鉴权。这个鉴权完成以后会把有效的用户信息放在一个Authentication中供以后的授权模块使用。在具体的鉴权过程中,使用了我们配置 好的各种Provider以及对应的UserDetailServiceEncoder类来完成相应的获取服务器端用户数据以及与用户输入的验证信息的 比对工作。

 

我们从FilterSecurityInterceptor我们从入手看看怎样进行授权的:

Java代码 

//这里是拦截器拦截HTTP请求的入口   

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)   

        throws IOException, ServletException {   

        FilterInvocation fi = new FilterInvocation(request, response, chain);   

        invoke(fi);   

    }   

//这是具体的拦截调用   

    public void invoke(FilterInvocation fi) throws IOException, ServletException {   

        if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)   

10             && observeOncePerRequest) {   

11            //在第一次进行过安全检查之后就不会再做了   

12             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());   

13         } else {   

14             //这是第一次收到相应的请求,需要做安全检测,同时把标志为设置好 -  FILTER_APPLIED,下次就再有请求就不会作相同的安全检查了   

15             if (fi.getRequest() != null) {   

16                 fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);   

17             }   

18             //这里是做安全检查的地方   

19             InterceptorStatusToken token = super.beforeInvocation(fi);   

20             //接着向拦截器链执行   

21             try {   

22                 fi.getChain().doFilter(fi.getRequest(), fi.getResponse());   

23             } finally {   

24                 super.afterInvocation(token, null);   

25             }   

26         }   

27     }  

Java代码 

28 //这里是拦截器拦截HTTP请求的入口  

29     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)  

30         throws IOException, ServletException {  

31         FilterInvocation fi = new FilterInvocation(request, response, chain);  

32         invoke(fi);  

33     }  

34 //这是具体的拦截调用  

35     public void invoke(FilterInvocation fi) throws IOException, ServletException {  

36         if ((fi.getRequest() != null) && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)  

37             && observeOncePerRequest) {  

38            //在第一次进行过安全检查之后就不会再做了  

39             fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  

40         } else {  

41             //这是第一次收到相应的请求,需要做安全检测,同时把标志为设置好 -  FILTER_APPLIED,下次就再有请求就不会作相同的安全检查了  

42             if (fi.getRequest() != null) {  

43                 fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);  

44             }  

45             //这里是做安全检查的地方  

46             InterceptorStatusToken token = super.beforeInvocation(fi);  

47             //接着向拦截器链执行  

48             try {  

49                 fi.getChain().doFilter(fi.getRequest(), fi.getResponse());  

50             } finally {  

51                 super.afterInvocation(token, null);  

52             }  

53         }  

54     }  


 我们看看在AbstractSecurityInterceptor是怎样对HTTP请求作安全检测的:

Java代码 

55 protected InterceptorStatusToken beforeInvocation(Object object) {   

56     Assert.notNull(object, "Object was null");   

57   

58     if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {   

59         throw new IllegalArgumentException("Security invocation attempted for object "  

60             + object.getClass().getName()   

61             + " but AbstractSecurityInterceptor only configured to support secure objects of type: "  

62             + getSecureObjectClass());   

63     }   

64     //这里读取配置FilterSecurityInterceptorObjectDefinitionSource属性,这些属性配置了资源的安全设置   

65     ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object);   

66   

67     if (attr == null) {   

68         if(rejectPublicInvocations) {   

69             throw new IllegalArgumentException(   

70                   "No public invocations are allowed via this AbstractSecurityInterceptor. "  

71                 + "This indicates a configuration error because the "  

72                 + "AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'");   

73         }   

74   

75         if (logger.isDebugEnabled()) {   

76             logger.debug("Public object - authentication not attempted");   

77         }   

78   

79         publishEvent(new PublicInvocationEvent(object));   

80   

81         return null// no further work post-invocation   

82     }   

83   

84   

85     if (logger.isDebugEnabled()) {   

86         logger.debug("Secure object: " + object.toString() + "; ConfigAttributes: " + attr.toString());   

87     }   

88     //这里从SecurityContextHolder中去取Authentication对象,一般在登录时会放到SecurityContextHolder中去   

89     if (SecurityContextHolder.getContext().getAuthentication() == null) {   

90         credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",   

91                 "An Authentication object was not found in the SecurityContext"), object, attr);   

92     }   

93   

94     // 如果前面没有处理鉴权,这里需要对鉴权进行处理   

95     Authentication authenticated;   

96   

97     if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() || alwaysReauthenticate) {   

98         try {//调用配置好的AuthenticationManager处理鉴权,如果鉴权不成功,抛出异常结束处理   

99             authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext()   

100                                                                                          .getAuthentication());   

101         } catch (AuthenticationException authenticationException) {   

102             throw authenticationException;   

103         }   

104   

105         // We don't authenticated.setAuthentication(true), because each provider should do that   

106         if (logger.isDebugEnabled()) {   

107             logger.debug("Successfully Authenticated: " + authenticated.toString());   

108         }   

109         //这里把鉴权成功后得到的Authentication保存到SecurityContextHolder中供下次使用   

110         SecurityContextHolder.getContext().setAuthentication(authenticated);   

111     } else {//这里处理前面已经通过鉴权的请求,先从SecurityContextHolder中去取得Authentication   

112         authenticated = SecurityContextHolder.getContext().getAuthentication();   

113   

114         if (logger.isDebugEnabled()) {   

115             logger.debug("Previously Authenticated: " + authenticated.toString());   

116         }   

117     }   

118   

119     // 这是处理授权的过程   

120     try {   

121         //调用配置好的AccessDecisionManager来进行授权   

122         this.accessDecisionManager.decide(authenticated, object, attr);   

123     } catch (AccessDeniedException accessDeniedException) {   

124         //授权不成功向外发布事件   

125         AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr, authenticated,   

126                 accessDeniedException);   

127         publishEvent(event);   

128   

129         throw accessDeniedException;   

130     }   

131   

132     if (logger.isDebugEnabled()) {   

133         logger.debug("Authorization successful");   

134     }   

135   

136     AuthorizedEvent event = new AuthorizedEvent(object, attr, authenticated);   

137     publishEvent(event);   

138   

139     // 这里构建一个RunAsManager来替代当前的Authentication对象,默认情况下使用的是NullRunAsManager会把SecurityContextHolder中的Authentication对象清空   

140     Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr);   

141   

142     if (runAs == null) {   

143         if (logger.isDebugEnabled()) {   

144             logger.debug("RunAsManager did not change Authentication object");   

145         }   

146   

147         // no further work post-invocation   

148         return new InterceptorStatusToken(authenticated, false, attr, object);   

149     } else {   

150         if (logger.isDebugEnabled()) {   

151             logger.debug("Switching to RunAs Authentication: " + runAs.toString());   

152         }   

153   

154         SecurityContextHolder.getContext().setAuthentication(runAs);   

155   

156         // revert to token.Authenticated post-invocation   

157         return new InterceptorStatusToken(authenticated, true, attr, object);   

158     }   

159 }  

Java代码 

160 protected InterceptorStatusToken beforeInvocation(Object object) {  

161     Assert.notNull(object, "Object was null");  

162   

163     if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {  

164         throw new IllegalArgumentException("Security invocation attempted for object "  

165             + object.getClass().getName()  

166             + " but AbstractSecurityInterceptor only configured to support secure objects of type: "  

167             + getSecureObjectClass());  

168     }  

169     //这里读取配置FilterSecurityInterceptorObjectDefinitionSource属性,这些属性配置了资源的安全设置  

170     ConfigAttributeDefinition attr = this.obtainObjectDefinitionSource().getAttributes(object);  

171   

172     if (attr == null) {  

173         if(rejectPublicInvocations) {  

174             throw new IllegalArgumentException(  

175                   "No public invocations are allowed via this AbstractSecurityInterceptor. "  

176                 + "This indicates a configuration error because the "  

177                 + "AbstractSecurityInterceptor.rejectPublicInvocations property is set to 'true'");  

178         }  

179   

180         if (logger.isDebugEnabled()) {  

181             logger.debug("Public object - authentication not attempted");  

182         }  

183   

184         publishEvent(new PublicInvocationEvent(object));  

185   

186         return null// no further work post-invocation  

187     }  

188   

189   

190     if (logger.isDebugEnabled()) {  

191         logger.debug("Secure object: " + object.toString() + "; ConfigAttributes: " + attr.toString());  

192     }  

193     //这里从SecurityContextHolder中去取Authentication对象,一般在登录时会放到SecurityContextHolder中去  

194     if (SecurityContextHolder.getContext().getAuthentication() == null) {  

195         credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",  

196                 "An Authentication object was not found in the SecurityContext"), object, attr);  

197     }  

198   

199     // 如果前面没有处理鉴权,这里需要对鉴权进行处理  

200     Authentication authenticated;  

201   

202     if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated() || alwaysReauthenticate) {  

203         try {//调用配置好的AuthenticationManager处理鉴权,如果鉴权不成功,抛出异常结束处理  

204             authenticated = this.authenticationManager.authenticate(SecurityContextHolder.getContext()  

205                                                                                          .getAuthentication());  

206         } catch (AuthenticationException authenticationException) {  

207             throw authenticationException;  

208         }  

209   

210         // We don't authenticated.setAuthentication(true), because each provider should do that  

211         if (logger.isDebugEnabled()) {  

212             logger.debug("Successfully Authenticated: " + authenticated.toString());  

213         }  

214         //这里把鉴权成功后得到的Authentication保存到SecurityContextHolder中供下次使用  

215         SecurityContextHolder.getContext().setAuthentication(authenticated);  

216     } else {//这里处理前面已经通过鉴权的请求,先从SecurityContextHolder中去取得Authentication  

217         authenticated = SecurityContextHolder.getContext().getAuthentication();  

218   

219         if (logger.isDebugEnabled()) {  

220             logger.debug("Previously Authenticated: " + authenticated.toString());  

221         }  

222     }  

223   

224     // 这是处理授权的过程  

225     try {  

226         //调用配置好的AccessDecisionManager来进行授权  

227         this.accessDecisionManager.decide(authenticated, object, attr);  

228     } catch (AccessDeniedException accessDeniedException) {  

229         //授权不成功向外发布事件  

230         AuthorizationFailureEvent event = new AuthorizationFailureEvent(object, attr, authenticated,  

231                 accessDeniedException);  

232         publishEvent(event);  

233   

234         throw accessDeniedException;  

235     }  

236   

237     if (logger.isDebugEnabled()) {  

238         logger.debug("Authorization successful");  

239     }  

240   

241     AuthorizedEvent event = new AuthorizedEvent(object, attr, authenticated);  

242     publishEvent(event);  

243   

244     // 这里构建一个RunAsManager来替代当前的Authentication对象,默认情况下使用的是NullRunAsManager会把SecurityContextHolder中的Authentication对象清空  

245     Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attr);  

246   

247     if (runAs == null) {  

248         if (logger.isDebugEnabled()) {  

249             logger.debug("RunAsManager did not change Authentication object");  

250         }  

251   

252         // no further work post-invocation  

253         return new InterceptorStatusToken(authenticated, false, attr, object);  

254     } else {  

255         if (logger.isDebugEnabled()) {  

256             logger.debug("Switching to RunAs Authentication: " + runAs.toString());  

257         }  

258   

259         SecurityContextHolder.getContext().setAuthentication(runAs);  

260   

261         // revert to token.Authenticated post-invocation  

262         return new InterceptorStatusToken(authenticated, true, attr, object);  

263     }  

264 }  


 到这里我们假设配置AffirmativeBased作为AccessDecisionManager

Java代码 

265 //这里定义了决策机制,需要全票才能通过   

266     public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)   

267         throws AccessDeniedException {   

268         //这里取得配置好的迭代器集合   

269         Iterator iter = this.getDecisionVoters().iterator();   

270         int deny = 0;   

271         //依次使用各个投票器进行投票,并对投票结果进行计票   

272         while (iter.hasNext()) {   

273             AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();   

274             int result = voter.vote(authentication, object, config);   

275             //这是对投票结果进行处理,如果遇到其中一票通过,那就授权通过,如果是弃权或者反对,那就继续投票   

276             switch (result) {   

277             case AccessDecisionVoter.ACCESS_GRANTED:   

278                 return;   

279   

280             case AccessDecisionVoter.ACCESS_DENIED:   

281             //这里对反对票进行计数   

282                 deny++;   

283   

284                 break;   

285   

286             default:   

287                 break;   

288             }   

289         }   

290         //如果有反对票,抛出异常,整个授权不通过   

291         if (deny > 0) {   

292             throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",   

293                     "Access is denied"));   

294         }   

295   

296         // 这里对弃权票进行处理,看看是全是弃权票的决定情况,默认是不通过,由allowIfAllAbstainDecisions变量控制   

297         checkAllowIfAllAbstainDecisions();   

298     }   

299 具体的投票由投票器进行,我们这里配置了RoleVoter来进行投票:   

300     public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {   

301         int result = ACCESS_ABSTAIN;   

302         //这里取得资源的安全配置   

303         Iterator iter = config.getConfigAttributes();   

304   

305         while (iter.hasNext()) {   

306             ConfigAttribute attribute = (ConfigAttribute) iter.next();   

307                

308             if (this.supports(attribute)) {   

309                 result = ACCESS_DENIED;   

310   

311                 // 这里对资源配置的安全授权级别进行判断,也就是匹配ROLE为前缀的角色配置   

312                 // 遍历每个配置属性,如果其中一个匹配该主体持有的GrantedAuthority,则访问被允许。   

313                 for (int i = 0; i < authentication.getAuthorities().length; i++) {   

314                     if (attribute.getAttribute().equals(authentication.getAuthorities()[i].getAuthority())) {   

315                         return ACCESS_GRANTED;   

316                     }   

317                 }   

318             }   

319         }   

320   

321         return result;   

322     }  

Java代码 

323 //这里定义了决策机制,需要全票才能通过  

324     public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)  

325         throws AccessDeniedException {  

326         //这里取得配置好的迭代器集合  

327         Iterator iter = this.getDecisionVoters().iterator();  

328         int deny = 0;  

329         //依次使用各个投票器进行投票,并对投票结果进行计票  

330         while (iter.hasNext()) {  

331             AccessDecisionVoter voter = (AccessDecisionVoter) iter.next();  

332             int result = voter.vote(authentication, object, config);  

333             //这是对投票结果进行处理,如果遇到其中一票通过,那就授权通过,如果是弃权或者反对,那就继续投票  

334             switch (result) {  

335             case AccessDecisionVoter.ACCESS_GRANTED:  

336                 return;  

337   

338             case AccessDecisionVoter.ACCESS_DENIED:  

339             //这里对反对票进行计数  

340                 deny++;  

341   

342                 break;  

343   

344             default:  

345                 break;  

346             }  

347         }  

348         //如果有反对票,抛出异常,整个授权不通过  

349         if (deny > 0) {  

350             throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",  

351                     "Access is denied"));  

352         }  

353   

354         // 这里对弃权票进行处理,看看是全是弃权票的决定情况,默认是不通过,由allowIfAllAbstainDecisions变量控制  

355         checkAllowIfAllAbstainDecisions();  

356     }  

357 具体的投票由投票器进行,我们这里配置了RoleVoter来进行投票:  

358     public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {  

359         int result = ACCESS_ABSTAIN;  

360         //这里取得资源的安全配置  

361         Iterator iter = config.getConfigAttributes();  

362   

363         while (iter.hasNext()) {  

364             ConfigAttribute attribute = (ConfigAttribute) iter.next();  

365               

366             if (this.supports(attribute)) {  

367                 result = ACCESS_DENIED;  

368   

369                 // 这里对资源配置的安全授权级别进行判断,也就是匹配ROLE为前缀的角色配置  

370                 // 遍历每个配置属性,如果其中一个匹配该主体持有的GrantedAuthority,则访问被允许。  

371                 for (int i = 0; i < authentication.getAuthorities().length; i++) {  

372                     if (attribute.getAttribute().equals(authentication.getAuthorities()[i].getAuthority())) {  

373                         return ACCESS_GRANTED;  

374                     }  

375                 }  

376             }  

377         }  

378   

379         return result;  

380     }  


 上面就是对整个授权过程的一个分析,从FilterSecurityInterceptor拦截Http请求入手,然后读取对资源的安全配置以后,把这些 信息交由AccessDecisionManager来进行决策,Spring为我们提供了若干决策器来使用,在决策器中我们可以配置投票器来完成投票, 我们在上面具体分析了角色投票器的使用过程。

 

 

 

 

 

 

分享到:
评论

相关推荐

    Spring源码分析.pdf

    Spring 源码分析 Spring 框架是 Java 语言中最流行的开源框架之一,它提供了一个强大且灵活的基础设施来构建企业级应用程序。在 Spring 框架中,IOC 容器扮演着核心角色,本文将深入分析 Spring 源码,了解 IOC ...

    spring源码分析(1-10)

    Spring 源代码分析系列涵盖了多个关键模块,包括事务处理、IoC容器、JDBC、MVC、AOP以及与Hibernate和Acegi安全框架的集成。以下是对这些知识点的详细阐述: 1. **Spring 事务处理**:Spring 提供了声明式事务管理...

    Spring源码分析.txt

    spring源码分析,百度云视频。链接如果失效了,请私聊我。

    spring源码分析专题学习资源

    spring源码分析专题,源码分析视频,对spring的源码进行分析

    Spring源码分析

    以上只是Spring源码分析的部分内容,实际源码中还包括Spring的其他模块,如Spring Batch(批处理)、Spring Security(安全)、Spring Integration(集成)等。理解并掌握Spring源码,有助于我们更好地利用Spring...

    Spring源码分析第一阶段

    Spring框架是开源的轻量级Java应用程序框架,主要目标是简化企业级应用程序的开发。它通过一套完整的设计模式和约定,实现了业务...通过深入分析Spring源码,我们可以更好地理解和利用这些功能来优化我们的应用程序。

    spring 源码分析CHM

    摘自javaEye 学习spring 源码的必备资料. 多多下载

    Spring5 源码分析(第 2 版)-某Tom老师

    《Spring5 源码分析(第 2 版)》是某Tom老师精心编写的深度解析文档,旨在帮助读者全面理解Spring5的核心机制和设计理念。Spring作为Java领域最为广泛应用的框架之一,其源码的深入理解对于开发者来说至关重要。这篇...

    Spring5 源码分析(第 2 版) .zip

    《Spring5 源码分析(第 2 版)》是针对Spring框架第五个主要版本的深度解析著作,由知名讲师倾心打造,旨在帮助读者深入理解Spring框架的内部工作机制,提升对Java企业级应用开发的专业技能。本书涵盖了Spring框架的...

    Tom_深入分析Spring源码

    《Spring源码分析》这份资料深入探讨了Spring框架的核心机制,尤其聚焦于Spring5版本。Spring作为Java领域中最重要的轻量级应用框架之一,它的设计理念、实现方式以及工作原理对于任何想成为优秀Java开发者的人都至...

    Spring源码分析_Spring_IOC

    ### Spring源码分析_Spring_IOC:深入理解Spring的IOC容器机制 #### 基本概念与核心作用 在探讨Spring框架的核心组件之一——IOC(Inversion of Control,控制反转)容器之前,首先需要理解它在Spring框架中的角色...

    spring源码分析

    《Spring源码分析》 Spring框架作为Java领域中不可或缺的一部分,其强大之处在于它提供了丰富的功能,包括依赖注入(Dependency Injection,简称DI)、面向切面编程(Aspect-Oriented Programming,简称AOP)、事务...

    spring 源码中文注释

    在源码分析的过程中,读者会深入理解Spring的内部工作机制,例如如何解析配置、如何创建bean实例、如何实现AOP代理等。这将有助于开发者编写更高效、更健壮的代码,也能为参与Spring的扩展或定制打下坚实基础。 总...

    Spring源码分析.rar

    《Spring源码分析》 Spring框架作为Java领域最流行的开源框架之一,它的设计思想和实现方式一直是许多开发者深入研究的对象。这份"Spring源码分析"资料深入探讨了Spring的核心机制,帮助我们理解其背后的原理,从而...

    Spring源码解析.zip

    本压缩包“Spring源码解析”提供了对Spring框架核心组件——IOC(Inversion of Control,控制反转)、AOP(Aspect Oriented Programming,面向切面编程)以及Transaction(事务管理)的源码分析,帮助开发者更全面地...

    Spring 源码分析文档----自用

    ### Spring 源码分析——设计模式篇 #### 一、引言 Spring框架作为Java企业级开发领域中不可或缺的一部分,其内部集成了多种设计模式,不仅有助于提高系统的可维护性和扩展性,还能够帮助开发者更好地理解和应用...

    五、Spring源码分析——Spring Aop

    《Spring AOP 源码分析》 在深入探讨Spring AOP之前,我们先要理解AOP(面向切面编程)的基本概念。AOP是一种编程范式,它将关注点分离,使得我们可以将横切关注点(如日志、事务管理、安全检查等)与业务逻辑解耦...

    spring源码分析流程全面解析

    在深入探讨Spring源码分析流程之前,我们先要理解Spring框架的基本概念。Spring是一个轻量级的Java企业级应用框架,它提供了丰富的功能,包括依赖注入(DI)、面向切面编程(AOP)、数据访问、事务管理等。Spring的...

    spring源码包.zip

    通过对这些模块的源码分析,我们可以深入了解Spring如何实现其强大的功能,并能更好地运用到实际项目中,提升代码质量和可维护性。无论是新手还是经验丰富的开发者,理解Spring的源码都将是一次宝贵的进阶之旅。

    二、Spring源码分析——BeanFactory

    《Spring源码分析——BeanFactory》 在Java的IoC(Inversion of Control)和DI(Dependency Injection)领域,Spring框架扮演着至关重要的角色。BeanFactory是Spring的核心组件之一,它是容器的基石,负责管理应用...

Global site tag (gtag.js) - Google Analytics