什么是依赖注入
Spring 能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系统需要重构时,代码的改写量将大大减少。 设值注入 //定义Person接口 public?interface?Person { //Person接口里定义一个使用斧子的方法 public?void?useAxe(); } 然后是Axe的接口 //定义Axe接口 public?interface?Axe { ????//Axe接口里有个砍的方法 ????public?void?chop(); } Person的实现类 //Chinese实现Person接口 public?class?Chinese?implements?Person { ????//面向Axe接口编程,而不是具体的实现类 ????private?Axe?axe; ????//默认的构造器 ????public?Chinese() ????{} ????//设值注入所需的setter方法 ????public?void?setAxe(Axe?axe) ????{ ????????this.axe?=?axe; ????} ????//实现Person接口的useAxe方法 ????public?void?useAxe() ????{ ????????System.out.println(axe.chop()); ????} } Axe的第一个实现类 //Axe的第一个实现类?StoneAxe public?class?StoneAxe?implements?Axe { ????//默认构造器 ????public?StoneAxe() ????{} ????//实现Axe接口的chop方法 ????public?String?chop() ????{ ????return?"石斧砍柴好慢"; ????} } 下面采用Spring的配置文件将Person实例和Axe实例组织在一起。配置文件如下所示: <!--?下面是标准的XML文件头?--> <?xml?version="1.0"?encoding="gb2312"?> <!--?下面一行定义Spring的XML配置文件的dtd?--> "http://www.springframework.org/dtd/spring-beans.dtd"> <!--?以上三行对所有的Spring配置文件都是相同的?--> <!--?Spring配置文件的根元素?--> <BEANS> <!—定义第一bean,该bean的id是chinese,?class指定该bean实例的实现类?--> <BEAN?class=lee.Chinese?id=chinese> <!--?property元素用来指定需要容器注入的属性,axe属性需要容器注入此处是设值注入,因此Chinese类必须拥有setAxe方法?--> <property?name="axe"> <!--?此处将另一个bean的引用注入给chinese?bean?--> <REF?local="”stoneAxe”/"> </property> </BEAN> <!--?定义stoneAxe?bean?--> <BEAN?class=lee.StoneAxe?id=stoneAxe?/> </BEANS> 从配置文件中,可以看到Spring管理bean的灵巧性。bean与bean之间的依赖关系放在配置文件里组织,而不是写在代码里。通过配置文件的 指定,Spring能精确地为每个bean注入属性。因此,配置文件里的bean的class元素,不能仅仅是接口,而必须是真正的实现类。 public?class?BeanTest { ????//主方法,程序的入口 ????public?static?void?main(String[]?args)throws?Exception ????{ ????//因为是独立的应用程序,显式地实例化Spring的上下文。 ????ApplicationContext?ctx?=?new?FileSystemXmlApplicationContext("bean.xml"); ????//通过Person?bean的id来获取bean实例,面向接口编程,因此 ????//此处强制类型转换为接口类型 ????Person?p?=?(Person)ctx.getBean("chinese"); ????//直接执行Person的userAxe()方法。 ????p.useAxe(); ????} } 程序的执行结果如下: <?xml?version="1.0"?> <!--?定义编译该项目的基本信息--> <PROJECT?name="spring"?default="."?basedir="."> <!--?定义编译和运行该项目时所需的库文件?--> <PATH?id=classpath> <!--?该路径下存放spring.jar和其他第三方类库?--> <FILESET?dir=../../lib> <INCLUDE?name="*.jar"?/> </FILESET> <!--?同时还需要引用已经编译过的class文件--> <PATHELEMENT?path="."?/> </PATH> <!--?编译全部的java文件--> <TARGET?description="Compile?all?source?code"?name="compile"> <!--?指定编译后的class文件的存放位置?--> <JAVAC?debug="true"?destdir="."> deprecation="false"?optimize="false"?failonerror="true"> <!--?指定需要编译的源文件的存放位置?--> <SRC?path="."?/> <!--?指定编译这些java文件需要的类库位置--> <CLASSPATH?refid="classpath"?/> </JAVAC> </TARGET> <!--?运行特定的主程序?--> <TARGET?description="run?the?main?class"?name="run"?depends="compile"> <!--?指定运行的主程序:lee.BeanTest。--> <JAVA?failonerror="true"?fork="yes"?classname="lee.BeanTest"> <!--?指定运行这些java文件需要的类库位置--> <CLASSPATH?refid="classpath"?/> </JAVA> </TARGET> </PROJECT> 如果需要改写Axe的实现类。或者说,提供另一个实现类给Person实例使用。Person接口、Chinese类都无须改变。只需提供另一个Axe的实现,然后对配置文件进行简单的修改即可。 //Axe的另一个实现类?SteelAxe public?class?SteelAxe?implements?Axe { ????//默认构造器 ????public?SteelAxe() ????{} ????//实现Axe接口的chop方法 ????public?String?chop() ????{ ????return?"钢斧砍柴真快"; ????} } 然后,修改原来的Spring配置文件,在其中增加如下一行: <!--?定义一个steelAxe?bean--> <BEAN?class=lee.SteelAxe?id=steelAxe?/> 该行重新定义了一个Axe的实现:SteelAxe。然后修改chinese bean的配置,将原来传入stoneAxe的地方改为传入steelAxe。也就是将 <REF?local="”stoneAxe”/"> 改成 <REF?local="”steelAxe”/"> 此时再次执行程序,将得到如下结果: 构造注入 //Chinese实现Person接口 public?class?Chinese?implements?Person { ????//面向Axe接口编程,而不是具体的实现类 ????private?Axe?axe; ????//默认的构造器 ????public?Chinese() ????{} ????//构造注入所需的带参数的构造器 ????public?Chinse(Axe?axe) ????{ ????this.axe?=?axe; ????} ????//实现Person接口的useAxe方法 ????public?void?useAxe() ????{ ????System.out.println(axe.chop()); ????} } 此时无须Chinese类里的setAxe方法,构造Person实例时,Spring为Person实例注入所依赖的Axe实例。构造注入的配置文件也需做简单的修改,修改后的配置文件如下: <!--?下面是标准的XML文件头?--> <xml?version="1.0"?encoding="gb2312"?> <!--?下面一行定义Spring的XML配置文件的dtd?--> "http://www.springframework.org/dtd/spring-beans.dtd"> <!--?以上三行对所有的Spring配置文件都是相同的?--> <!--?Spring配置文件的根元素?--> <BEANS> <!—定义第一个bean,该bean的id是chinese,?class指定该bean实例的实现类?--> <BEAN?class=lee.Chinese?id=chinese> </BEAN> <!--?定义stoneAxe?bean?--> <BEAN?class=lee.SteelAxe?id=steelAxe?/> </BEANS> 执行效果与使用steelAxe设值注入时的执行效果完全一样。区别在于:创建Person实例中Axe属性的时机不同——设值注入是现创建一个默认的bean实例,然后调用对应的构造方法注入依赖关系。而构造注入则在创建bean实例时,已经完成了依赖关系的 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |