<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[friend365 - Spring]]></title>
<link>http://www.friend365.cn/</link>
<description><![CDATA[敬业是对渴望成功的人对待工作的基本要求，思想决定行为，行为形成习惯，习惯决定性格，性格决定命运。永久域名www.friend365.cn]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005-2009 friend365.cn]]></copyright>
<webMaster><![CDATA[friend365@163.com(美丽人生)]]></webMaster>
<generator>friend365.cn</generator> 
<image>
	<title>friend365</title> 
	<url>http://www.friend365.cn/images/logomy.gif</url> 
	<link>http://www.friend365.cn/</link> 
	<description>friend365</description> 
</image>

			<item>
			<link>http://www.friend365.cn/default.asp?id=1122</link>
			<title><![CDATA[爱恨交加：OSGi的Spring和EJB之路？]]></title>
			<author>friend365@163.com(51itcn)</author>
			<category><![CDATA[Spring]]></category>
			<pubDate>Wed,04 Nov 2009 08:43:31 +0800</pubDate>
			<guid>http://www.friend365.cn/default.asp?id=1122</guid>	
		<description><![CDATA[对于OSGi，有人评论称OSGi是“Spring之后的下一个big thing”。不过该文的作者后来又觉得，OSGi也有不少的问题，其中之一就是它在把技术变得复杂化。作者是这样说的：<br/><br/>51CTO编辑推荐：OSGi入门与实践全攻略<br/><br/>我对OSGi不怀疑并承认OSGi解决了许多问题，而且它支持一些出众的结构模型比如高模块化（high modularization）以及微服务（micro services）。然而从另外一个角度来说，在使用了OSGi几年之后，也体验了它在不同领域的表现（我是指开发领域）之后，我真的开始怀疑OSGi了。<br/><br/>这是我喜欢和讨厌的OSGi的一些方面：<br/><br/>它从几百个具有代表性的小bundle中创建出一个系统的概念非常棒。OSGi bundle很好的一点是它们定义了边界：不仅从依赖关系的意义上，而且从运行时间的意义上也是这样。每个bundle可以充当一个微应用，有自己的lifecycle和用户，每个bundle能够仔细地断定出哪个对象对外暴露。好好地使用它们，会带给系统以松耦合，并增加再使用的可能性。而与此同时，OSGi的lifecycle使life更加复杂。实际上，追踪服务和管理服务所引发的各个问题很讨厌（我曾看到过在它们的bundle activators使用大型的state machines来管理所有事情，这种样板化代码没有人愿意写）。幸运的是有Spring DM来帮我们管理这些。坦白说，如果没有Spring DM我绝不会动手开始OSGi项目。尽管Spring DM大大降低了bundle启动的复杂度，但仍然很麻烦。我仍然需要启动OSGi的运行时间、安装启动bundles，我还需要确保所有其他我所需要的bundles已经安装和启动。<br/><br/>我个人觉得，作为开发者，我们应当迫使自己执行系统的约束。我们不得不自动核对定义的限制，比如说，如果我们读取了一些我们并不想读取的类，构建程序就会失败。OSGi的版本概念，通过定义输入和输出包，将架构参数（architectural constraints）首次带入开发者的日常生活，并引入了一系列新的问题。OSGi是这样解决运行时间的版本问题的：它给每个bundle自己的class loader，并让class loader看起来像它所在的版本一样。这也带来一系列问题，因为它改变了你环境工作的方式。你的代码在所有你的单元测试中都可以通过，但一旦执行在OSGi的运行时间上，就会崩溃；Libraries崩溃因为这提升了运行时间中的类；Singletons被设计为静态对象不止一次地被创建，周而复始。当你在不断地调整你的模块构建说明时你会经常终止，而且绝对会在你的整个系统中传播反直观的依赖关系。Spring DM也是这个问题：通过在你的服务中添加一些指令并且不断地调整你的class loaders，你仍然需要调整和传送依赖关系。<br/><br/>尤其是类的导入更是带来很麻烦的问题。你很快会注意到，没有强大和自动集成的测试组件来配合OSGi，你无法继续下去。<br/><br/>现在说一下我的结论：<br/><br/>在考虑OSGi之前，我会切实核实是否在不关闭系统的情况下我能否在运行时间中转换bundles，即使在这种情况下，我也会再次查看这些需求，来看看是否我会把他们限制在一个角落里，在这里我可以使用其他技术在动态时间上来动态地加载模块。还有其他选择可以生成这种结构条例（比如使用一个IOC container，使用独立的container来执行模块依赖等等……）许多这些东西都很接近KISS原则，避免所有其他附件的样板化代码并构建配置，这因此让你更加敏捷。<br/><br/>回归到我的题目上，还有一种技术拥有这样的特点（我是指让技术更加复杂），那就是EJB。Spring是最流行的实例：技术更加复杂，开发周期更加困难。也许我们会在未来的几年内在OSGi中看到同样的境遇？我无法断定，时间将验证一切。<br/><br/>]]></description>
		</item>
		
			<item>
			<link>http://www.friend365.cn/default.asp?id=930</link>
			<title><![CDATA[先进的开发框架—理解什么是Spring ]]></title>
			<author>friend365@163.com(51itcn)</author>
			<category><![CDATA[Spring]]></category>
			<pubDate>Fri,13 Jun 2008 09:58:03 +0800</pubDate>
			<guid>http://www.friend365.cn/default.asp?id=930</guid>	
		<description><![CDATA[-. Spring诞生<br/>Spring是一个开源框架，目前在开源社区的人气很旺，被认为是最有前途的开源框架之一。她是由Rod Johnson创建的，她的诞生是为了简化企业级系统的开发。说道Spring就不得不说EJB，因为Spring在某种意义上是EJB的替代品，她是一种轻量级的容器。用过EJB的人都知道EJB很复杂，为了一个简单的功能你不得不编写多个Java文件和部署文件，他是一种重量级的容器。也许你不了解EJB，你可能对“轻（重）量级”和“容器”比较陌生，那么这里我简单介绍一下。<br/>1、什么是容器<br/>“容器”，这个概念困扰我好久。从学习Tomcat开始就一直对此感到困惑。感性的来讲，容器就是可以用来装东西的物品。那么在编程领域就是指用来装对象（OO的思想，如果你连OO都不了解，建议你去学习OO先）的对象。然而这个对象比较特别，它不仅要容纳其他对象，还要维护各个对象之间的关系。这么讲可能还是太抽象，来看一个简单的例子：<br/>代码片断1：<br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.friend365.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>public class Container&nbsp;&nbsp;<br/>{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;public void init() <br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;Speaker s = new Speaker(); <br/>&nbsp;&nbsp;&nbsp;&nbsp;Greeting g = new Greeting(s); <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>} <br/></div></div><br/>可以看到这里的Container类（容器）在初始化的时候会生成一个Speaker对象和一个Greeting对象，并且维持了它们的关系，当系统要用这些对象的时候，直接问容器要就可以了。这就是容器最基本的功能，维护系统中的实例（对象）。如果到这里你还是感到模糊的话，别担心，我后面还会有相关的解释。<br/><br/>2、轻量级与重量级<br/>所谓“重量级”是相对于“轻量级”来讲的，也可以说“轻量级”是相对于重量级来讲的。在Spring出现之前，企业级开发一般都采用EJB，因为它提供的事务管理，声明式事务支持，持久化，分布计算等等都“简化”了企业级应用的开发。我这里的“简化”打了双引号，因为这是相对的。重量级容器是一种入侵式的，也就是说你要用EJB提供的功能就必须在你的代码中体现出来你使用的是EJB，比如继承一个接口，声明一个成员变量。这样就把你的代码绑定在EJB技术上了，而且EJB需要JBOSS这样的容器支持，所以称之为“重量级”。<br/>相对而言“轻量级”就是非入侵式的，用Spring开发的系统中的类不需要依赖Spring中的类，不需要容器支持（当然Spring本身是一个容器），而且Spring的大小和运行开支都很微量。一般来说，如果系统不需要分布计算或者声明式事务支持那么Spring是一个更好的选择。<br/><br/>二、&nbsp;&nbsp;&nbsp;&nbsp;几个核心概念<br/>在我看来Spring的核心就是两个概念，反向控制（IoC），面向切面编程（AOP）。还有一个相关的概念是POJO，我也会略带介绍。<br/>1、POJO<br/>我所看到过的POJO全称有两个，Plain o&#114;dinary Java Object，Plain Old Java Object，两个差不多，意思都是普通的Java类，所以也不用去管谁对谁错。POJO可以看做是简单的JavaBean（具有一系列Getter，Setter方法的类）。严格区分这里面的概念没有太大意义，了解一下就行。<br/>2、&nbsp;&nbsp;&nbsp;&nbsp;IoC<br/>IoC的全称是Inversion of Control，中文翻译反向控制或者逆向控制。这里的反向是相对EJB来讲的。EJB使用JNDI来查找需要的对象，是主动的，而Spring是把依赖的对象注入给相应的类（这里涉及到另外一个概念“依赖注入”，稍后解释），是被动的，所以称之为“反向”。先看一段代码，这里的区别就很容易理解了。<br/>代码片段2：<br/><br/><div class="UBBPanel"><div class="UBBTitle"><img src="http://www.friend365.cn/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>public void greet() <br/>{ <br/>Speaker s = new Speaker(); <br/>s.sayHello(); <br/>} <br/></div></div><br/><br/>代码片段3：<br/><br/>public void greet() <br/>{ <br/>Speaker s = (Speaker)context.lookup(&#34;ejb/Speaker&#34;); <br/>s.sayHello(); <br/>} <br/><br/>代码片段4：<br/><br/>public class Greeting&nbsp;&nbsp;<br/>{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;public Speaker s; <br/>&nbsp;&nbsp;&nbsp;&nbsp;public Greeting(Speaker s) <br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.s = s; <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>&nbsp;&nbsp;&nbsp;&nbsp;public void greet() <br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.sayHello(); <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>} <br/>我们可以对比一下这三段代码。其中片段2是不用容器的编码，片段3是EJB编码，片段4是Spring编码。结合代码片段1，你能看出来Spring编码的优越之处吗？也许你会觉得Spring的编码是最复杂的。不过没关系，我在后面会解释Spring编码的好处。<br/>这里我想先解释一下“依赖注入”。根据我给的例子可以看出，Greeting类依赖Speaker类。片段2和片段3都是主动的去获取Speaker，虽然获取的方式不同。但是片段4并没有去获取或者实例化Speaker类，而是在greeting函数中直接使用了s。你也许很容易就发现了，在构造函数中有一个s被注入（可能你平时用的是，传入）。在哪里注入的呢？请回头看一下代码片段1，这就是使用容器的好处，由容器来维护各个类之间的依赖关系（一般通过Setter来注入依赖，而不是构造函数，我这里是为了简化示例代码）。Greeting并不需要关心Speaker是哪里来的或是从哪里获得Speaker，只需要关注自己分内的事情，也就是让Speaker说一句问候的话。<br/>3、&nbsp;&nbsp;&nbsp;&nbsp;AOP<br/>AOP全称是Aspect-Oriented Programming，中文翻译是面向方面的编程或者面向切面的编程。你应该熟悉面向过程的编程，面向对象的编程，但是面向切面的编程你也许是第一次听说。其实这些概念听起来很玄，说到底也就是一句话的事情。<br/>现在的系统往往强调减小模块之间的耦合度，AOP技术就是用来帮助实现这一目标的。举例来说，假如上文的Greeting系统含有日志模块，安全模块，事务管理模块，那么每一次greet的时候，都会有这三个模块参与，以日志模块为例，每次greet之后，都要记录下greet的内容。而对于Speaker或者Greeting对象来说，它们并不知道自己的行为被记录下来了，它们还是像以前一样的工作，并没有任何区别。只是容器控制了日志行为。如果这里你有点糊涂，没关系，等讲到具体Spring配置和实现的时候你就明白了。<br/>假如我们现在为Greeting系统加入一个Valediction功能，那么AOP模式的系统结构如下：<br/>G|RET|TIN|G<br/>V|ALE|DIT|ION<br/>|&nbsp;&nbsp; |&nbsp;&nbsp; |<br/>日志 安全 事务<br/><br/>这些模块是贯穿在整个系统中的，为系统的不同的功能提供服务，可以称每个模块是一个“切面”。其实“切面”是一种抽象，把系统不同部分的公共行为抽取出来形成一个独立的模块，并且在适当的地方（也就是切入点，后文会解释）把这些被抽取出来的功能再插入系统的不同部分。<br/>从某种角度上来讲“切面”是一个非常形象的描述，它好像在系统的功能之上横切一刀，要想让系统的功能继续，就必须先过了这个切面。这些切面监视并拦截系统的行为，在某些（被指定的）行为执行之前或之后执行一些附加的任务（比如记录日志）。而系统的功能流程（比如Greeting）并不知道这些切面的存在，更不依赖于这些切面，这样就降低了系统模块之间的耦合度。<br/><br/>三、&nbsp;&nbsp;&nbsp;&nbsp;Spring初体验<br/>这一节我用一个具体的例子Greeting，来说明使用Spring开发的一般流程和方法，以及Spring配置文件的写法。<br/>首先创建一个Speaker类，你可以把这个类看做是POJO。<br/>代码片段5：<br/><br/>public class Speaker&nbsp;&nbsp;<br/>{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;public void sayHello() <br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&#34;Hello!&#34;); <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>} <br/>再创建一个Greeting类。<br/>代码片段6：<br/><br/>public class Greeting&nbsp;&nbsp;<br/>{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;private Speaker speaker; <br/>&nbsp;&nbsp;&nbsp;&nbsp;public void setSpeaker(Speaker speaker) <br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.speaker = speaker; <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>&nbsp;&nbsp;&nbsp;&nbsp;public void greet() <br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;speaker.sayHello(); <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>} <br/><br/>然后要创建一个Spring的配置文件把这两个类关联起来。<br/>代码片段7（applicationContext.xml）：<br/><br/>&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt; <br/>&#34;-//SPRING//DTD BEAN//EN&#34;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#34;<a href="http://www.springframework.org/dtd/spring-beans.dtd" target="_blank">http://www.springframework.org/dtd/spring-beans.dtd</a>&#34;&gt; <br/><br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&#34;Speaker&#34; class=&#34;Speaker&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&#34;Greeting&#34; class=&#34;Greeting&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#34;speaker&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#34;Speaker&#34;/&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>要用Spring Framework必须把Spring的包加入到Classpath中，我用的是Eclipse+MyEclipse，这些工作是自动完成的。推荐用Spring的配置文件编辑器来编辑，纯手工编写很容易出错。我先分析一下这个xml文件的结构，然后再做测试。从节点开始，先声明了两个，第二个bean有一个speaker属性（property）要求被注入，注入的内容是另外一个bean Speaker。这里的命名是符合JavaBean规范的，也就是说如果是speaker属性，那么Spring容器就会调用setSpeaker()来注入这个属性。是reference的意思，表示引用另外一个bean。<br/>下面看一段简单的测试代码：<br/>代码片段8：<br/><br/>public static void main(String[] args)&nbsp;&nbsp;<br/>{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ApplicationContext context =&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;New ClassPathXmlApplicationContext(&#34;applicationContext.xml&#34;); <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Greeting greeting = (Greeting)context.getBean(&#34;Greeting&#34;); <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;greeting.greet(); <br/>} <br/><br/>这段代码很简单，如果你上文都看懂了，那么这里应该没有问题。值得注意的是Spring有两种方式来创建容器（我们不再用上文我们自己编写的Container），一种是ApplicationContext，另外一种是BeanFactory。ApplicationContext更强大一些，而且使用上两者没有太大区别，所以一般说来都用ApplicationContext。Spring容器帮助我们维护我们在配置文件中声明的Bean以及它们之间的依赖关系，我们的Bean只需要关注自己的核心业务。<br/><br/>四、&nbsp;&nbsp;&nbsp;&nbsp;面向接口的编程<br/>看了这么多，也许你并没有觉得Spring给开发带来了很多便利。那是因为我举的例子还不能突出Spring的优越之处，接下来我将通过接口编程来体现Spring的强大。<br/>假如现在要求扩展Greeting的功能，要让Speaker用不同的语言来问候，也就是说有不同的Speaker，比如ChineseSpeaker, EnglishSpeaker。那么对上文提到的三种编码方式（代码片段2、3、4）分别加以修改，你会发现很麻烦。假如下次又要加入一个西班牙语，又得重复劳动。很自然的会考虑到使用一个ISpeaker接口来简化工作,，更改后的代码如下（这里没有列出接口的相关代码，我想你应该明白怎么写）：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/><br/>代码片段9：<br/><br/>public void greet() <br/>{ <br/>ISpeaker s = new ChineseSpeaker(); <br/>s.sayHello(); <br/>} <br/><br/>代码片段10：<br/><br/>public void greet() <br/>{ <br/>ISpeaker s = (ISpeaker)context.lookup(&#34;ejb/ChineseSpeaker&#34;); <br/>s.sayHello(); <br/>} <br/><br/>代码片段11：<br/><br/>public class Greeting&nbsp;&nbsp;<br/>{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;public ISpeaker s; <br/>&nbsp;&nbsp;&nbsp;&nbsp;public Greet(ISpeaker s) <br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.s = s; <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>&nbsp;&nbsp;&nbsp;&nbsp;public void greet() <br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.sayHello(); <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>} <br/>对比三段代码，你会发现，第一种方法还是把具体的Speaker硬编码到代码中了，第二中方法稍微好一点，但是没有本质改变，而第三种方法就不一样了，代码中并没有关于具体Speaker的信息。也就是说，如果下次还有什么改动的话，第三种方法的Greeting类是不需要修改，编译的。根据上文Spring的使用介绍，只需要改动xml文件就能给Greeting注入不同的Speaker了，这样代码的扩展性是不是提高了很多？<br/>关于Spring的接口编程还有很多东西可以去挖掘，后文还会提到有关Spring Proxy的接口编程，我这里先介绍这么多，有兴趣话可以去google更多的资料。<br/><br/>五、&nbsp;&nbsp;&nbsp;&nbsp;应用Spring中的切面<br/>Spring生来支持AOP，首先来看几个概念：<br/>1、&nbsp;&nbsp;&nbsp;&nbsp;切面（Aspect）：切面是系统中抽象出来的的某一个功能模块，上文已经有过介绍，这里不再多说。<br/>2、&nbsp;&nbsp;&nbsp;&nbsp;通知（Advice）：通知是切面的具体实现。也就是说你的切面要完成什么功能，具体怎么做就是在通知里面完成的。这个名称似乎有点让人费解，等后面看了代码就明白了。<br/>3、&nbsp;&nbsp;&nbsp;&nbsp;切入点（Pointcut）：切入点定义了通知应该应用到系统的哪些地方。Spring只能控制到方法（有的AOP框架可以控制到属性），也就是说你能在方法调用之前或者之后选择切入，执行额外的操作。<br/>4、&nbsp;&nbsp;&nbsp;&nbsp;目标对象（Target）：目标对象是被通知的对象。它可以是任何类，包括你自己编写的或者第三方类。有了AOP以后，目标对象就只需要关注自己的核心业务，其他的功能，比如日志，就由AOP框架支持完成。<br/>5、&nbsp;&nbsp;&nbsp;&nbsp;代理（Proxy）：简单的讲，代理就是将通知应用到目标对象后产生的对象。Spring在运行时会给每个目标对象生成一个代理对象，以后所有对目标对象的操作都会通过代理对象来完成。只有这样通知才可能切入目标对象。对系统的其他部分来说，这个过程是透明的，也就是看起来跟没用代理一样。<br/>我为了简化，只介绍这5个概念。通过这几个概念应该能够理解Spring的切面编程了。如果需要深入了解Spring AOP的话再去学习其他概念也很快的。<br/>下面通过一个实际的例子来说明Spring的切面编程。继续上文Greeting的例子，我们想在Speaker每次说话之前记录Speaker被调用了。<br/>首先创建一个LogAdvice类：<br/>代码片段12：<br/><br/>public class LogAdvice implements MethodBeforeAdvice&nbsp;&nbsp;<br/>{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;public void before(Method arg0, Object[] arg1, Object arg2)throws Throwable&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;{ <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&#34;Speaker called!&#34;); <br/>&nbsp;&nbsp;&nbsp;&nbsp;} <br/>} <br/>这里涉及到一个类，MethodBeforeAdvice，这个类是Spring类库提供的，类似的还有AfterReturningAdvice等等，从字面就能理解它们的含义。先不急着理解这个类，我稍后解释。我们继续看如何把这个类应用到我们的系统中去。<br/>代码片段13：<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;&#34;Speaker&#34; class=&#34;Speaker&#34;/&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&#34;Greeting&#34; class=&#34;Greeting&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#34;speaker&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#34;SpeakerProxy&#34;/&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&#34;LogAdvice&#34; class=&#34;LogAdvice&#34;/&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&#34;SpeakerProxy&#34; class=&#34;org.springframework.aop.framework.ProxyFactoryBean&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#34;proxyInterfaces&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ISpeaker <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#34;interceptorNames&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LogAdvice <br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#34;target&#34;&gt; <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#34;Speaker&#34;/&gt; <br/>可以看到我们的配置文件中多了两个bean，一个LogAdvice，另外一个SpeakerProxy。LogAdvice很简单。我着重分析一下SpeakerProxy。这个Bean实际上是由Spring提供的ProxyFactoryBean实现。下面定义了三个依赖注入的属性。<br/>1、&nbsp;&nbsp;&nbsp;&nbsp;proxyInterfactes：这个属性定义了这个Proxy要实现哪些接口，可以是一个，也可以是多个（多个的话，要用list标签）。我前面讲过Proxy是在运行是动态创建的，那么这个属性就告诉Spring创建这个Proxy的时候实现哪些接口。<br/>2、&nbsp;&nbsp;&nbsp;&nbsp;interceptorNames：这个属性定义了Proxy被切入了哪些通知，这里只有一个LogAdvice。<br/>3、&nbsp;&nbsp;&nbsp;&nbsp;target：这个属性定义了被代理的对象。在这个例子中target是Speaker。<br/>这样的定义实际上约束了被代理的对象必须实现一个接口，这与上文讲的面向接口的编程有点类似。其实可以这样理解，接口的定义可以让系统的其他部分不受影响，以前用ISpeaker接口来调用，现在加入了Proxy还是一样的。但实际上内容已经不一样了，以前是Speaker，现在是一个Proxy。而target属性让proxy知道具体的方法实现在哪里。Proxy可以看作是target的一个包装。当然Spring并没有强制要求用接口，通过CGLIB（一个高效的代码生成开源类库）也可以直接根据目标对象生成子类，但这种方式并不推荐。<br/>我们还像以前一样的测试我们的Greeting系统，测试代码和代码片段8是一样的。运行结果如下：<br/>Speaker called!<br/>Hello!<br/>看到效果了吧！而且你可以发现，我们加入Log功能并没有改变以前的代码，甚至测试代码都没有改变，这就是AOP的魅力所在！我们更改的只是配置文件。<br/>下面解释一下刚才落下的MethodBeforeAdvice。关于这个类我并不详细介绍，因为这涉及到Spring中的另外一个概念“连接点（Jointpoint）”，我详细介绍一个before这个方法。这个方法有三个参数arg0表示目标对象在哪个点被切入了，既然是MethodBeforeAdvice，那当然是在Method之前被切入了。那么arg0就是表示的那个Method。第二个参数arg1是Method的参数，所以类型是Object[]。第三个参数就是目标对象了，在Greeting例子中arg2的类型实际上是Speaker。<br/>在Greeting例子中，我们并没有指定目标对象的哪些方法要被切入，而是默认切入所有方法调用（虽然Speaker只有一个方法）。通过自定义Pointcut，可以控制切入点，我这里不再介绍了，因为这并不影响理解Spring AOP，有兴趣的话去google一下就知道了。 <br/>]]></description>
		</item>
		
			<item>
			<link>http://www.friend365.cn/default.asp?id=663</link>
			<title><![CDATA[spring 编程入门十大问题解答]]></title>
			<author>friend365@163.com(51itcn)</author>
			<category><![CDATA[Spring]]></category>
			<pubDate>Mon,31 Mar 2008 14:58:40 +0800</pubDate>
			<guid>http://www.friend365.cn/default.asp?id=663</guid>	
		<description><![CDATA[spring 编程入门十大问题解答<br/><br/>1、如何学习Spring？<br/>你可以通过下列途径学习spring：<br/>(1) spring下载包中doc目录下的MVC-step-by-step和sample目录下的例子都是比较好的spring开发的例子。 <br/>(2) AppFuse集成了目前最流行的几个开源轻量级框架或者工具Ant,XDoclet,Spring,Hibernate(iBATIS),JUnit,Cactus,StrutsTestCase,Canoo&#39;s WebTest,Struts Menu,Display Tag Library,OSCache,JSTL,Struts 。<br/>你可以通过AppFuse源代码来学习spring。<br/>AppFuse网站：<a href="http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse" target="_blank">http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse</a><br/><br/>(3)Spring 开发指南(夏昕)（<a href="http://www.xiaxin.net/Spring_Dev_Guide.rar" target="_blank">http://www.xiaxin.net/Spring_Dev_Guide.rar</a>）<br/>一本spring的入门书籍,里面介绍了反转控制和依赖注射的概念，以及spring的bean管理，spring的MVC，spring和hibernte，iBatis的结合。<br/><br/>(4) spring学习的中文论坛<br/>SpringFramework中文论坛(<a href="http://spring.jactiongroup.net/" target="_blank">http://spring.jactiongroup.net/</a>)<br/>Java视线论坛(<a href="http://forum.javaeye.com/" target="_blank">http://forum.javaeye.com/</a>)的spring栏目<br/><br/>2、利用Spring框架编程，console打印出log4j:WARN Please initialize the log4j system properly？<br/>说明你的log4j.properties没有配置。请把log4j.properties放到工程的classpath中，eclipse的classpath为bin目录，由于编译后src目录下的文件会拷贝到bin目录下，所以你可以把log4j.properties放到src目录下。<br/>这里给出一个log4j.properties的例子：<br/><br/>log4j.rootLogger=DEBUG,stdout<br/>log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br/>log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br/>log4j.appender.stdout.layout.ConversionPattern=%d %5p (%F:%L) - %m%n<br/><br/><br/>3、出现 java.lang.NoClassDefFoundError?<br/>一般情况下是由于你没有把必要的jar包放到lib中。<br/><br/>比如你要采用spring和hibernate（带事务支持的话），你除了spring.jar外还需要hibernat.jar、aopalliance.jar、cglig.jar、jakarta-commons下的几个jar包。<br/><br/><a href="http://www.springframework.org/download.html" target="_blank">http://www.springframework.org/download.html</a>下载spring开发包，提供两种zip包<br/>spring-framework-1.1.3-with-dependencies.zip和spring-framework-1.1.3.zip，我建议你下载spring-framework-1.1.3-with-dependencies.zip。这个zip解压缩后比后者多一个lib目录，其中有hibernate、j2ee、dom4j、aopalliance、jakarta-commons等常用包。<br/><br/>4、java.io.FileNotFoundException: Could not open class path resource [....hbm.xml],提示找不到xml文件？<br/>原因一般有两个：<br/>(1)该xml文件没有在classpath中。<br/>(2)applicationContext-hibernate.xml中的xml名字没有带包名。比如：<br/>&lt;bean id=&#34;sessionFactory&#34; class=&#34;org.springframework.orm.hibernate.LocalSessionFactoryBean&#34;&gt;<br/>&lt;property name=&#34;dataSource&#34;&gt;&lt;ref bean=&#34;dataSource&#34;/&gt;&lt;/property&gt;<br/>&lt;property name=&#34;mappingResources&#34;&gt;<br/>&lt;list&gt;<br/>&lt;value&gt;User.hbm.xml&lt;/value&gt; 错，改为： &lt;value&gt;com/yz/spring/domain/User.hbm.xml&lt;/value&gt;<br/>&lt;/list&gt;<br/>&lt;/property&gt;<br/>&lt;property name=&#34;hibernateProperties&#34;&gt;<br/>&lt;props&gt; <br/>&lt;prop key=&#34;hibernate.dialect&#34;&gt; net.sf.hibernate.dialect.MySQLDialect &lt;/prop&gt; <br/>&lt;prop key=&#34;hibernate.show_sql&#34;&gt;true&lt;/prop&gt; <br/>&lt;/props&gt; <br/>&lt;/property&gt;<br/>&lt;/bean&gt;<br/><br/><br/>5、org.springframework.beans.NotWritablePropertyException: Invalid property &#39;postDao&#39; of bean class？<br/>出现异常的原因是在application-xxx.xml中property name的错误。<br/>&lt;property name=&#34;....&#34;&gt; 中name的名字是与bean的set方法相关的，而且要注意大小写。<br/>比如<br/>public class PostManageImpl extends BaseManage implements PostManage {<br/>private PostDAO dao = null;<br/>public void setPostDAO(PostDAO postDAO){<br/>this.dao = postDAO;<br/>}<br/>}<br/>那么xml的定义应该是：<br/>&lt;bean id=&#34;postManage&#34; parent=&#34;txProxyTemplate&#34;&gt;<br/>&lt;property name=&#34;target&#34;&gt;<br/>&lt;bean class=&#34;com.yz.spring.service.implement.PostManageImpl&#34;&gt;<br/>&lt;property name=&#34;postDAO&#34;&gt;&lt;ref bean=&#34;postDAO&#34;/&gt;&lt;/property&gt; 对<br/>&lt;property name=&#34;dao&#34;&gt;&lt;ref bean=&#34;postDAO&#34;/&gt;&lt;/property&gt; 错 &lt;/bean&gt;<br/>&lt;/property&gt;<br/>&lt;/bean&gt;<br/><br/>6、Spring中如何实现事务管理？<br/>首先，如果使用mysql，确定mysql为InnoDB类型。<br/>事务管理的控制应该放到商业逻辑层。你可以写个处理商业逻辑的JavaBean，在该JavaBean中调用DAO，然后把该Bean的方法纳入spring的事务管理。<br/><br/>比如：xml文件定义如下：<br/>&lt;bean id=&#34;txProxyTemplate&#34; abstract=&#34;true&#34;<br/>class=&#34;org.springframework.transaction.interceptor.TransactionProxyFactoryBean&#34;&gt;<br/>&lt;property name=&#34;transactionManager&#34;&gt;&lt;ref bean=&#34;transactionManager&#34;/&gt;&lt;/property&gt;<br/>&lt;property name=&#34;transactionAttributes&#34;&gt;<br/>&lt;props&gt;<br/>&lt;prop key=&#34;save*&#34;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br/>&lt;prop key=&#34;remove*&#34;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br/>&lt;prop key=&#34;*&#34;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;<br/>&lt;/props&gt;<br/>&lt;/property&gt;<br/>&lt;/bean&gt;<br/><br/>&lt;bean id=&#34;userManage&#34; parent=&#34;txProxyTemplate&#34;&gt;<br/>&lt;property name=&#34;target&#34;&gt;<br/>&lt;bean class=&#34;com.yz.spring.service.implement.UserManageImpl&#34;&gt;<br/>&lt;property name=&#34;userDAO&#34;&gt;&lt;ref bean=&#34;userDAO&#34;/&gt;&lt;/property&gt;<br/>&lt;/bean&gt;<br/>&lt;/property&gt;<br/>&lt;/bean&gt;<br/><br/>com.yz.spring.service.implement.UserManageImpl就是我们的实现商业逻辑的JavaBean。我们通过parent元素声明其事务支持。<br/><br/>7、如何管理Spring框架下更多的JavaBean？<br/>JavaBean越多，spring配置文件就越大，这样不易维护。为了使配置清晰，我们可以将JavaBean分类管理，放在不同的配置文件中。 应用启动时将所有的xml同时加载。<br/>比如：<br/>DAO层的JavaBean放到applicationContext-hibernate.xml中，商业逻辑层的JavaBean放到applicationContext-service.xml中。然后启动类中调用以下代码载入所有的ApplicationContext。<br/><br/>String[] paths = {&#34;com/yz/spring/dao/hibernate/applicationContext-hibernate.xml&#34;,<br/>&#34;com/yz/spring/service/applicationContext-service.xml&#34;};<br/>ctx = new ClassPathXmlApplicationContext(paths);<br/><br/><br/>8、web应用中如何加载ApplicationContext？<br/>可以通过定义web.xml，由web容器自动加载。<br/><br/>&lt;servlet&gt;<br/>&lt;servlet-name&gt;context&lt;/servlet-name&gt;<br/>&lt;servlet-class&gt;org.springframework.web.context.ContextLoaderServlet&lt;/servlet-class&gt;<br/>&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br/>&lt;/servlet&gt;<br/><br/>&lt;context-param&gt;<br/>&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;<br/>&lt;param-value&gt;/WEB-INF/applicationContext-hibernate.xml&lt;/param-value&gt;<br/>&lt;param-value&gt;/WEB-INF/applicationContext-service.xml&lt;/param-value&gt;<br/>&lt;/context-param&gt;<br/><br/>9、在spring中如何配置的log4j?<br/>在web.xml中加入以下代码即可。<br/>&lt;context-param&gt;<br/>&lt;param-name&gt;log4jConfigLocation&lt;/param-name&gt;<br/>&lt;param-value&gt;/WEB-INF/log4j.properties&lt;/param-value&gt;<br/>&lt;/context-param&gt;<br/><br/>10、Spring框架入门的编程问题解决了，我该如何更深地领会Spring框架呢？<br/>这两本书你该去看看。这两本书是由Spring的作者Rod Johnson编写的。<br/>Expert One on one J2EE Design and Development<br/>Expert One on one J2EE Development Without EJB<br/>你也该看看martinfowler的Inversion of Control Containers and the Dependency Injection pattern。<br/><a href="http://www.martinfowler.com/articles/injection.html" target="_blank">http://www.martinfowler.com/articles/injection.html</a><br/><br/>再好好研读一下spring的文档。]]></description>
		</item>
		
			<item>
			<link>http://www.friend365.cn/default.asp?id=475</link>
			<title><![CDATA[Spring JMS 消息处理]]></title>
			<author>friend365@163.com(admin)</author>
			<category><![CDATA[Spring]]></category>
			<pubDate>Mon,21 Jan 2008 10:21:52 +0800</pubDate>
			<guid>http://www.friend365.cn/default.asp?id=475</guid>	
		<description><![CDATA[在 Spring 系列 的第 4 期也是最后一期中，我将介绍 Spring JMS（Java 消息服务）框架的特性。JMS PG 定义了 Java 应用程序通过面向消息的中间件（MOM）创建和交换消息的标准途径。<br/>就像在这个系列前面的文章中一样，我将使用一个简单的示例来演示 Spring JMS 的特性。您将随我一道开发一个点对点的（P2P）基于消息的系统，使用 Spring JMS 框架通过 JMS 接口与 IBM 的 WebSphere MQ 集成。完成练习后，将可以通过这个系统发送和接收简单的文本消息。<br/>Spring JMS<br/>Spring 的 JMS 抽象框架简化了 JMS API 的使用，并与 JMS 提供者（比如 IBM 的 WebSphere MQ 5.3）平滑地集成。org.springframework.jms.core 包提供了在 Spring 中使用 JMS 的核心功能。它的模板类处理资源的创建和释放，简化了 JMS 的使用。<br/>像其他大多数 Spring 模板类一样，JMS 模板类提供了执行公共操作的 helper 方法。在需要更复杂应用的情况下，类把处理任务的核心委托给用户实现的回调接口。JMS 类提供了方便的方法，用来发送消息、同步地使用消息以及向用户公开 JMS 会话和消息的制作者。<br/>以下 JMS 包和 o&#114;g.springframework.jms.core 一起构成了 Spring JMS 的功能：<br/>o&#114;g.springframework.jms.support <br/>提供转换 JMSException 的功能。转换代码把检测到的 JMSException 层次结构转换成未检测到异常的镜像层次结构。 <br/>o&#114;g.springframework.jms.support.converter <br/>提供 MessageConverter 抽象，以在 Java 对象和 JMS 消息之间进行转换。 <br/>o&#114;g.springframework.jms.support.destination <br/>提供管理 JMS 目标的不同策略，比如针对 JNDI 中保存的目标的服务定位器。 <br/>o&#114;g.springframework.jms.connection <br/>提供适合在独立应用程序中使用的 ConnectionFactory 实现。connection 还包含针对 JMS 的 Spring PlatformTransactionManager 实现。它允许把 JMS 作为事务性资源集成到 Spring 的事务管理机制中。<br/>IBM WebSphere MQ<br/>就像前面提到的，示例应用程序会用 Spring 的 JMS 框架通过 JMS 接口与 IBM 的 WebSphere MQ 集成。通过在应用程序和 Web 服务之间传递消息，WebSphere MQ 提供了可靠的、有恢复能力的应用程序集成。它使用队列和事务性工具帮助保持消息跨网络的完整性。WebSphere MQ 降低了信息丢失的风险和调和通信 IT 系统的需要。<br/>WebSphere MQ 在它所支持的所有平台上提供了一致的应用程序编程接口，这有助于让集成的程序可移植。除了标准接口外，WebSphere MQ 还完整实现了JMS 接口，包括对发布-订阅消息传递的支持。WebSphere MQ Explorer 工具可以远程地管理和配置整个 MQ 网络。管理和配置工具基于开放源码的 Eclipse 框架，而且是可扩展的。<br/>Spring JMS 模板<br/>Spring 框架提供了 JmsTemplate 的两个实现。JmsTemplate 类使用 JMS 1.1 API，子类 JmsTemplate102 则使用 JMS 1.0.2 API。我的示例应用程序使用的是 JmsTemplate102。<br/>JMS 模板被用来发送和接收 JMS 消息。Spring 采用回调机制对 JMS 信息传递进行协调。MessageCreator 回调接口用 JmsTemplate 中的调用代码提供的 Session 创建消息。为了支持 JMS API 更复杂的应用，回调 SessionCallback 向用户提供了 JMS 会话，而 callback ProducerCallback 则公开了 Session 和 MessageProducer 组合。<br/>]]></description>
		</item>
		
</channel>
</rss>