【前面的话】
Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring。不知道为什么对Spring有一种莫名的喜欢感,也许是因为他的名字,有一种希望的感觉。
Spring学习过程中的总结和心得,本文介绍了在初次学习Spring的时候,对于依赖注入的理解,希望有时间可以进行更深入的学习。请选择性阅读。
本文由牲口TT在博客园首次发表,转载请保持文章的完整性并注明:
作者:牲口TT。
链接:http://www.cnblogs.com/xt0810/p/3593853.html
【Spring介绍】
Spring Framework 是一个开源的Java/Java EE全功能栈(full-stack)的应用程序框架,以Apache许可证形式发布,也有.NET平台上的移植版本。该框架基于 Expert One-on-One Java EE Design and Development(ISBN 0-7645-4385-7)一书中的代码,最初由 Rod Johnson 和 Juergen Hoeller等开发。Spring Framework 提供了一个简易的开发方式,这种开发方式,将避免那些可能致使底层代码变得繁杂混乱的大量的属性文件和帮助类。
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
【依赖注入】
在学习Spring的时候,总是会遇到这个名词,就是依赖注入,所以首先学习什么是依赖注入。通过几个例子,说明什么是依赖注入,什么是spring下的依赖注入。
我们举一个Person开car的例子,希望通过这个例子可以更好的学习和理解什么是依赖注入。当然举得例子都是很简单的情形,在实际项目中可能要比这些复杂的多。
一、第一种情形:紧耦合情形,开宝马。
1. 分析如下:
定义三个类,Person.java、BaoMa.java、MainTest.java。如下面的代码,Person在它的构造函数中创建了Baoma对象,这就让Person类和Baoma类紧密的耦合在了一起,而且现在Person类只能开宝马,如果现在想要开奥迪,Person类是不能够处理的,除非修改Person这个类,这就使得两个类在紧耦合的情况下逻辑变得不够清晰,如果业务逻辑复杂,这些紧耦合的情形就会更多,带来代码难以测试,难以复用,难以理解等很多弊端。再加上让Person类来管理Baoma类的对象创建也是不合理的,因为面向对象的思想来说,Person类是没有管理Baoma类的对象的职责的。
2. 代码如下:
1)Person.java
1 public class Person { 2 private BaoMa baoma; 3 public Person(){ 4 baoma=new BaoMa();//Person和Baoma这个类紧耦合 5 } 6 public void driver(){ 7 baoma.GuaDang(); 8 baoma.CaiYouMen(); 9 baoma.DaFangXiang(); 10 } 11 }
2)BaoMa.java
public class BaoMa { public void GuaDang(){ System.out.println("我是宝马车,我在进行挂档"); } public void CaiYouMen(){ System.out.println("我是宝马车,我在进行踩油门"); } public void DaFangXiang(){ System.out.println("我是宝马车,我在进行打方向盘"); } }
3)MainTest.java
public class MainTest { public static void main(String[] args){ Person boy =new Person(); boy.driver(); } }
3. 运行结果:
我是宝马车,我在进行挂档
我是宝马车,我在进行踩油门
我是宝马车,我在进行打方向盘
二、第一种情形:紧耦合情形,开奥迪。
1. 分析如下:
从上面的代码中,我们如果想要开奥迪,只能对Person类进行修改,依次类推,如果开车人每次想要开的车不同,就需要每次对于Person类进行修改,这对于Person类来说是不合理的,Person类只关心我要开车,我有一个driver方法,我每次想要开车就是调用driver方法,所以这种紧耦合的编码是不够理想的。
2. 代码如下:
1) Person.java
1 public class Person { 2 private AuDi audi; 3 public Person(){ 4 audi=new AuDi(); 5 } 6 public void driver(){ 7 audi.GuaDang(); 8 audi.CaiYouMen(); 9 audi.DaFangXiang(); 10 } 11 }
2) AuDi.java
1 public class AuDi { 2 public void GuaDang(){ 3 System.out.println("我是奥迪车,我在进行挂档"); 4 } 5 public void CaiYouMen(){ 6 System.out.println("我是奥迪车,我在进行踩油门"); 7 } 8 public void DaFangXiang(){ 9 System.out.println("我是奥迪车,我在进行打方向盘"); 10 } 11 }
3) MainTest.java
1 public class MainTest { 2 public static void main(String[] args){ 3 Person boy =new Person(); 4 boy.driver(); 5 } 6 }
3. 运行结果:
1 我是奥迪车,我在进行挂档 2 我是奥迪车,我在进行踩油门 3 我是奥迪车,我在进行打方向盘
三、第二种情形:简单的依赖注入情形。
1. 分析如下:
在java的设计思想中,依赖注入的核心思想就是这种具体类之间的依赖,尽量转换成抽象依赖,也就是如下代码一样,Person类的依赖于抽象的Car类,而不是具体的Baoma类或者具体的AuDi类,分析见代码注释。
2. 代码如下:
1) Person.java
1 public class Person { 2 private Car car; 3 public Person(Car car){//构造器注入,传入的是car,也就是一个所有车型都必须实现的接口 4 this.car =car;//这里可以响应奥迪,宝马等任何一种车的实现。 5 }//这里Person类没有与任何特定类型的车发生耦合,对于Person来说,任何一种特定的车,只需要实现Car接口即可。具体是哪一种车型,对Person来说无关紧要。 6 public void driver(){ 7 car.GuaDang(); 8 car.CaiYouMen(); 9 car.DaFangXiang(); 10 } 11 }
2) Car.java
1 public interface Car { 2 public abstract void GuaDang(); 3 public abstract void CaiYouMen(); 4 public abstract void DaFangXiang(); 5 }
3) AuDi.java
1 public class AuDi implements Car { 2 public void GuaDang(){ 3 System.out.println("我是奥迪车,我在进行挂档"); 4 } 5 public void CaiYouMen(){ 6 System.out.println("我是奥迪车,我在进行踩油门"); 7 } 8 public void DaFangXiang(){ 9 System.out.println("我是奥迪车,我在进行打方向盘"); 10 } 11 }
4) MainTest.java
1 public class MainTest { 2 public static void main(String[] args){ 3 AuDi audi=new AuDi(); 4 Person boy =new Person(audi); 5 boy.driver(); 6 } 7 }
3. 运行结果:
1 我是奥迪车,我在进行挂档 2 我是奥迪车,我在进行踩油门 3 我是奥迪车,我在进行打方向盘
四、第三种情形:Spring的依赖注入情形。
1. 分析如下:
通过上面的说明,现在对于依赖注入应该有一个较好的理解了,那么Spring是如何实现IOC的?
通过依赖注入,对象的依赖关系将由负责协调系统中各个对象的第三方组件在创建对象时设定。对象无需自行创建或管理它们的依赖关系——依赖关系将自动注入到需要它们的对像中去。Spring就是这样的第三方组件,通过使用Spring框架,使得类之间的依赖关系通过Spring来进行管理。
具体的Spring进行依赖注入的方式和方法有时间在进行学习总结,今天只是对于Spring依赖注入的理解学习。
2. 代码如下:
1)Person.java
1 public class Person { 2 private Car car; 3 public Person(Car car){//构造器注入,传入的是car,也就是一个所有车型都必须实现的接口 4 this.car =car;//这里可以响应奥迪,宝马等任何一种车的实现。 5 }//这里Person类没有与任何特定类型的车发生耦合,对于Person来说,任何一种特定的车,只需要实现Car接口即可。具体是哪一种车型,对Person来说无关紧要。 6 public void driver(){ 7 car.GuaDang(); 8 car.CaiYouMen(); 9 car.DaFangXiang(); 10 } 11 }
2) Car.java
1 public interface Car { 2 public abstract void GuaDang(); 3 public abstract void CaiYouMen(); 4 public abstract void DaFangXiang(); 5 }
3) AuDi.java
1 public class AuDi implements Car { 2 public void GuaDang(){ 3 System.out.println("我是奥迪车,我在进行挂档"); 4 } 5 public void CaiYouMen(){ 6 System.out.println("我是奥迪车,我在进行踩油门"); 7 } 8 public void DaFangXiang(){ 9 System.out.println("我是奥迪车,我在进行打方向盘"); 10 } 11 12 }
4) cartest.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context-3.0.xsd"> 10 <bean id="cartest" class="Person"> 11 <constructor-arg ref="Car" /> 12 </bean> 13 <bean id="Car" class="AuDi" /> 14 </beans>
5)MainTest.java
1 import org.springframework.context.ApplicationContext; 2 import org.springframework.context.support.ClassPathXmlApplicationContext; 3 public class MainTest { 4 public static void main(String[] args){ 5 ApplicationContext context = new ClassPathXmlApplicationContext("cartest.xml"); 6 Person boy =(Person) context.getBean("cartest"); 7 boy.driver(); 8 } 9 }
3. 运行结果:
1 我是奥迪车,我在进行挂档 2 我是奥迪车,我在进行踩油门 3 我是奥迪车,我在进行打方向盘
【注意问题】
在编写上面的第四中的代码,需要注意一些问题,对于新手来说,可能会遇到错误。在这里说明一下:
一、首先需要导入如下的jar包。
- org.springframework.context-3.0.2.RELEASE.jar(点击可下载)
- org.springframework.beans-3.0.2.RELEASE.jar(点击可下载)
- org.springframework.core-3.0.2.RELEASE.jar(点击可下载)
- commons-logging-1.0.4.jar(点击可下载)
- org.springframework.asm-3.0.1.RELEASE-A.jar(点击可下载)
- org.springframework.expression-3.0.1.RELEASE-A.jar(点击可下载)
二、代码的结构如下图:
红线的地方在同一目录下。
三、可能遇到的错误
1. 错误:
The type org.springframework.core.NestedRuntimeException cannot be resolved. It is indirectly referenced from required .class files
解决办法:
导入:org.springframework.core-3.0.2.RELEASE
2. 错误:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
解决办法:
导入:commons-logging-1.0.4
3. 错误:
Caused by: java.lang.ClassNotFoundException: org.springframework.asm.ClassVisitor
解决办法:
导入:org.springframework.asm-3.0.1.RELEASE-A
4. 错误:
org.springframework.expression.PropertyAccessor
解决办法:
导入:org.springframework.expression-3.0.1.RELEASE-A
【参考资料】
1. 《Spring in action》 Craig Walls著 耿渊 张卫滨译