spring入门学习笔记第三课--spring的注入

来源:互联网 发布:一键复制淘宝店铺 编辑:程序博客网 时间:2024/06/10 15:55

spring的一个核心功能就是依赖注入,有的叫依赖注入(DI),也有的叫控制反转(IOC),但实际上在某种程度上,他们是差不多的。

我学习spring接触到的第一个概念就是DI,

通俗的解释就是:

在我们常规编程中,如果需要使用某个的方法,我们通常会new一个该对象的实例,然后调用方法,就像这样:

现有A和B两个类,我们想要在B类中调用的methodA方法。

Object Apublic class A{/** *这是我们想要调用的方法 **/public void methodA(){ //逻辑....}}}

我们通常在B类中会这样用:

public class B{public void methodB(){//我们会先new一个A的对象A a=new A();//然后调用A的方法a.methodA();}}
这种是比较常规的方法,即:如果我们使用某个对象的方法,我们需要手动创建这个对象。

但是IOC就提供了另外一种思维方式,就是不在由我们去创建这个类,而是由spring去创建这个类。

举一个生活中简单的例子,

在以前,如果我们需要一件新衣服,我们往往会这样做:

去布店裁点布,然后我们回家自己做。

也就是说,如果我们需要新衣服,我们需要自己做。

但是现在就不同了,现在如果我们需要一件新衣服,我们可以通过各种渠道购入,比如网上购物,比如商场。

这样,当我们需要新衣服的时候,我们就不需要自己去做了,相对于以前,不仅省了大量的时间,而且衣服的款式也多种多样。

回到spring这里,其实这里spring就承担类似于商场或者网店这样的角色,

我们不需要自己去做衣服,我们只要告诉spring我们需要什么样的衣服,spring会自动给我们提供。

如果放到代码里,大概就是这个样子的。

首先,我们需要构建一个spring项目:

项目的结构如下:


首先定义一个服装的接口,这个接口定义了如何展示这件衣服:

package com.panda.clothes.inter;/** * 定义服装接口 * @author Panda * */public interface BaseClothes {/** * 展示衣服的方法 */public void showClothes();}
然后,编写两个类,分别实现服装接口。

package com.panda.clothes.inter.impl;import com.panda.clothes.inter.BaseClothes;/** * 西装类 * 该类实现了衣服的接口 * @author Panda * */public class BusinessSuit implements BaseClothes {public void showClothes() {System.out.println("Clothes`s Name:"+"BusinessSuit");System.out.println("Clothes`s price:"+"$1000.0");System.out.println("Clothes`s Color:"+"black");}}
package com.panda.clothes.inter.impl;import com.panda.clothes.inter.BaseClothes;/** * T恤衫类 * 该类实现服装接口 * @author Panda * */public class TShirt implements BaseClothes {public void showClothes() {System.out.println("Clothes`s Name:"+"TShirt");System.out.println("Clothes`s price:"+"$150.0");System.out.println("Clothes`s Color:"+"white");}}
接下来编写测试类,

首先是我们比较常用的方式:

首先构建一个实例,然后调用方法

/** * 常规的使用方法 */@org.junit.Testpublic void conventionTest(){//首先创建一个服装对象,然后对其赋值。BaseClothes clothes=new BusinessSuit();//然后调用服装的展示方法clothes.showClothes();}
运行结果如下:

Clothes`s Name:BusinessSuit
Clothes`s price:$1000.0
Clothes`s Color:black

但是,如果我们突然不想要西装了,我们想要T恤,我们就需要对代码修改

/** * 常规的使用方法 */@org.junit.Testpublic void conventionTest(){//如果此时我们不想要西装,我们想要T恤。我们就需要实例化T恤而不是西装。//BaseClothes clothes=new BusinessSuit();//重新构造BaseClothes clothes=new TShirt();//然后调用服装的展示方法clothes.showClothes();}
运行结果如下:

Clothes`s Name:TShirt
Clothes`s price:$150.0
Clothes`s Color:white

这样我们就会发现,当我们对衣服需要变更时,我们需要修改代码。如果只有两件衣服还好一点,但是当业务逻辑更加复杂时,我们很可能都不知道自己需要改多少代码。

但是spring为我们提供了一种优秀的解决办法,也就是DI。

spring的DI有三种,

分别是:

1.接口注入

2.构造注入

3.set注入

首先我们展示第一种注入方式,接口注入,如果我们需要使用接口注入的话,需要提供一个接口,该接口提供被调用类的初始化方法。

package com.panda.clothes.test;import com.panda.clothes.inter.BaseClothes;public interface InterfaceInject {    public void CreateClothes(BaseClothes clothes);       public BaseClothes getClothes();}
然后,任何需要使用clothes实例的类,都要继承这个类

package com.panda.clothes.test;import com.panda.clothes.inter.BaseClothes;public class InterfaceInjectImpl implements InterfaceInject {    private BaseClothes clothes;        public void CreateClothes(BaseClothes clothes) {        this.clothes = clothes;    }    public BaseClothes getClothes(){                return this.clothes;            }}
最后,我们编写测试类。
package com.panda.clothes.test;import com.panda.clothes.inter.BaseClothes;import com.panda.clothes.inter.impl.TShirt;public class InterfaceTest {//首先获取clothes的实例InterfaceInject ifi=new InterfaceInjectImpl();@org.junit.Testpublic void test(){    //提供clothes的实例    ifi.CreateClothes(new TShirt());    //获取clothes的实例    BaseClothes clothes=ifi.getClothes();    //调用clothes的展示方法    clothes.showClothes();}}

输出结果如下:

Clothes`s Name:TShirt
Clothes`s price:$150.0
Clothes`s Color:white
这样做有什么作用呢?

在我们常规的方法中,调用类直接依赖被调用类,使用接口注入我们就可以将依赖分离到接口层次,然后具体的实现我们可以通过配置文件或其他方式来加载。

但是这种方式依然具备很强的侵略性,所以实际应用有限。

其实关于接口注入,我也是有点迷糊,似懂非懂的感觉,做个标记,之后等完全弄清楚再回来补一个详细的。


2017/03/03补充:接口注入和注入接口的区别

整理这篇内容的时候,在这我遇到一个问题,就是接口注入和注入接口有什么本质的区别,毕竟看起来这个东西最终的实现和注入接口的方式是一样的,而且还多了一层,更复杂了.

关于这个问题问了好多人,今天终于获得了一个比较通俗的解释,

使用接口注入这种方式,我们可以在中转接口中,定义一些指定的业务处理,做一些校验等操作,类似于服务定位模式.

比直接注入接口多了一层封装.


spring中使用最多的方式就是set注入,setter注入通过提供属性值的getter/setter方法来注入需要的实例。

继续使用之前的BaseClothes接口和BusinessSuit以及TShirt实例。

然后我们新建一个测试类:

在测试类中提供一个BaseClothes参数,并提供她的getter/setter方法。

package com.panda.clothes.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.panda.clothes.inter.BaseClothes;public class SetterTest {    //提供BaseClothes字段private BaseClothes clothes;    //提供BaseClothes的getter/setter方法public BaseClothes getClothes() {    return clothes;}public void setClothes(BaseClothes clothes) {       System.out.println("set注入调用属性的setter方法");    this.clothes = clothes;}@org.junit.Testpublic void Test(){    ApplicationContext atc=new ClassPathXmlApplicationContext("spring-demo.xml");    SetterTest ses=(SetterTest) atc.getBean("setterTest");    ses.getClothes().showClothes();}}
之后我们在SRC下新建一个spring-demo.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 调用类 --><bean id="setterTest" class="com.panda.clothes.test.SetterTest"><property name="clothes" ref="businessSuit"></property></bean><!-- 服装 --><!-- 西装 --><bean id="businessSuit" class="com.panda.clothes.inter.impl.BusinessSuit" /><!-- T恤 --><bean id="tShirt" class="com.panda.clothes.inter.impl.TShirt"></bean></beans>
运行测试类:
set注入调用属性的setter方法
Clothes`s Name:BusinessSuit
Clothes`s price:$1000.0
Clothes`s Color:black

这种在配置文件中通过property属性进行配置则默认采用的set注入。

最后一种注入方式为构造注入:

只需要稍微修改一下配置文件和测试类:

测试类去除getter/setter方法,添加一个构造方法

public class SetterTest {//提供BaseClothes字段private BaseClothes clothes;//提供BaseClothes的getter/setter方法public  SetterTest(BaseClothes clothes) {// TODO Auto-generated constructor stubthis.clothes=clothes;}public static void main(String []args){ApplicationContext atc=new ClassPathXmlApplicationContext("spring-demo.xml");SetterTest ses=(SetterTest) atc.getBean("setterTest");ses.clothes.showClothes();}

配置文件:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd">       <!-- 调用类 --><bean  id="setterTest" class="com.panda.clothes.test.SetterTest"> <constructor-arg index="0" ref="tShirt" /></bean><!-- 服装 --><!-- 西装 --><bean id="businessSuit" class="com.panda.clothes.inter.impl.BusinessSuit" /><!-- T恤 --><bean id="tShirt" class="com.panda.clothes.inter.impl.TShirt"/></beans>
这种通过constructor-arg注入的方法叫做构造注入,他是通过构造方法进行注入。

这三种方法常用的是set注入也叫设置注入,

通过这种方法,我们可以直观明确的了解我们注入的是什么,但是因为我们提供了setter方法,所以我们不能确定相关的数据成员会不会被改变。

而通过构造注入的方法,一方面符合了java的编码规则,在类创建是就得到一个完整的实例,另一方面我们也可以通过构造参数的顺序来控制我们实例化的顺序,但是这种方法当我们需要实例化较多数据时,构造器会比较臃肿,而且参数太多,也不太容易记忆。




0 0