spring依赖注入方式

来源:互联网 发布:js如何获取自定义属性 编辑:程序博客网 时间:2024/06/05 07:34

平常应用Spring开发中,用得最多的是容器。spring容器帮我们实例化对象并且注入到需要该对象的类中。 
spring有多种依赖注入的形式,下面仅介绍spring通过xml进行IOC配置的方式:

一、Setter注入

set注入是最简单常用的注入方式,《【Spring学习03】Spring简单入门实例 》中就是用的set注入。 
Order类中需要用到NotifyService对象,于是定义了一个private的NotifyService成员变量,然后创建了名为setNotifyService的set方法,这个set方法就是注入的入口。 
setNotifyService方法命名是有讲究的。(基于在配置文件中,我们定义了注入的属性:<property name="notifyservice" ref="notify"/>)。 
set必须小写,后面跟的第一个字母大小写不限,再后面则必须要和xml配置中的property name一致。因此我们也可以命名为setNotifyservice,但不能命名成setNotifyService。

代码如下:

public class Order {    /*要注入的对象*/    private NotifyService notifyservice;    /*notifyservice不是在内部new()出来的,    而是通过指定方法传进来的,也就是我们说的注入。这里是setter方法注入*/    public void setNotifyservice(NotifyService notifyservice) {        this.notifyservice = notifyservice;    }    /*订单支付完成后,系统通知老板*/    public void PaySuccess(){        notifyservice.sendMessage("客户张铁蛋完成订单2017079657付款,共人民币:97.5元");    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

然后编写spring的xml文件:

<bean id="notify" class="twm.spring.start.NotifyServiceByCellPhoneImpl" /><bean id="order" class="twm.spring.start.Order" >    <!-- 配置要注入的对象 -->    <property name="notifyservice" ref="notify"/></bean>
  • 1
  • 2
  • 3
  • 4
  • 5

<bean>中的id属性是bean的标识,必须唯一。class属性是类的完全限定名,指明由哪个类来实例化。 
<property>是用来指明要注入的属性和对象的。因为我们要注入Order中的私有成员notifyService,所以要在<bean>标签中创建一个<property>标签指定notifyService对象。<property>标签中的name就是就是注入方法名去掉前面的set,剩下的这一截首字母大小写可不限。ref指向要注入的对象(id)。对象是引用实例,所以要用ref,如果是传值,则用value。

另外要注意的是:property name只和注入方法名相关,和内部属性名没有半毛关系。所以order类改成下面这样也是可以的:

public class Order {    private NotifyService notifyservice_suibian;    public void setnotifyservice(NotifyService notifyservice) {        this.notifyservice_suibian = notifyservice;    }    /*订单支付完成后,系统通知老板*/    public void PaySuccess(){        notifyservice_suibian.sendMessage("客户张铁蛋完成订单2017079657付款,共人民币:97.5元");    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

二、构造器注入

构造函数也是一个注入点。现在我们把上例的setter注入改为构造注入。 
首先删除setNotifyservice方法,改成构造函数:

/*构造函数注入*/public Order(NotifyService notifyservice1) {    this.notifyservice1 = notifyservice1;}
  • 1
  • 2
  • 3
  • 4

相应的beans.xml修改: 
<property name="notifyservice" ref="notify"/> 
改为<constructor-arg ref="notify"></constructor-arg> 
这样就完成了构造器注入。

<constructor-arg>顾名思义就是构造函数参数,因为这里只有一个参数,所以直接指向需要注入的对象bean id就行了。 
多个参数时,怎么配置呢?比如我们把order修改为:

public class Order {    private String username;    private String orderno;    private NotifyService notifyservice1;    /*构造函数注入*/    public Order(String username, String orderno, NotifyService notifyservice1) {        this.username = username;        this.orderno = orderno;        this.notifyservice1 = notifyservice1;    }    /*订单支付完成后,系统通知老板*/    public void PaySuccess(){        notifyservice1.sendMessage("客户"+username+"完成订单"+orderno+"付款,共人民币:97.5元");    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这时配置beans.xml就有讲究了,spring提供了几种方法: 
1、智能识别

<bean id="order" class="twm.spring.start.Order" >    <constructor-arg value="张老三"></constructor-arg>    <constructor-arg ref="notify"></constructor-arg>    <constructor-arg value="1234567"></constructor-arg></bean>
  • 1
  • 2
  • 3
  • 4
  • 5

<constructor-arg>没有别的属性。Spring这时会先按类型排序,同类型的按先后顺序向构造函数参数赋值。所以如果完全按照构造函数的参数顺序写,肯定是没有问题的。上面这样写,也是没有问题的,两个String类型的参数顺序对了就行。

2、指明参数类型。

<bean id="order" class="twm.spring.start.Order" >    <constructor-arg type="String" value="张老三"></constructor-arg>    <constructor-arg type="twm.spring.start.NotifyService" ref="notify"></constructor-arg>    <constructor-arg type="String" value="1234567"></constructor-arg></bean>
  • 1
  • 2
  • 3
  • 4
  • 5

和1智能识别一样,Spring会先按类型区分,同类型的按先后顺序向构造函数参数赋值。

3、指定参数名

<bean id="order" class="twm.spring.start.Order" >    <constructor-arg name="username" value="张老三"></constructor-arg>    <constructor-arg name="notifyservice1" ref="notify"></constructor-arg>    <constructor-arg name="orderno" value="1234567"></constructor-arg></bean>
  • 1
  • 2
  • 3
  • 4
  • 5

这样Spring会完全按照构造函数的形参名字匹配。

4、指定索引index

<bean id="order" class="twm.spring.start.Order" >    <constructor-arg index="0" value="张老三"></constructor-arg>    <constructor-arg index="2" ref="notify"></constructor-arg>    <constructor-arg index="1" value="2017877997"></constructor-arg></bean>
  • 1
  • 2
  • 3
  • 4
  • 5

指定的索引顺序一定要和类型匹配,不然会报错。构造函数有2个相同类型的参数,指定索引可以解决此种情况。 
注意index是从0开始。

构造注入对比setter注入

何时使用构造注入,何时使用setter注入,经验法则是:强制依赖用构造,可选依赖用Setter。注意,在settter方法上使用@Required注解即可令属性强制依赖。

Spring 团队建议,构造注入的实例是不可变的,不为null的。此外,构造注入组件要将完全初始化后的实例返回给客户端代码。还有,大量参数的构造函数是非常烂的,它意味着该类有大量的职责,得重构。

setter注入主要用于可选依赖,类内部可以指定默认依赖。否则类内所有使用依赖的地方,都得进行非空校验。setter注入的有个好处就是,类可以重配置或者再注入。因此,使用JMXMBeans进行管理的场景中,就非常适合setter注入。

使用何种依赖注入方式,对于某些类,非常有意义。有时协同第三方类处理,没有源码,由你来决定使用何种方式。比如,第三方类未暴露任何setter方法,那么构造注入也许就是唯一的可行的注入方式了。

三、静态工厂的方法注入

静态工厂,就是通过调用静态工厂的方法来获取自己需要的对象,为了让spring管理所有对象,我们不能直接通过”工程类.静态方法()”来获取对象,而是依然通过spring注入的形式获取。 
在上例的基础上,增加一个工厂类:

NotifyFactory.java:

public class NotifyFactory {    /*静态工厂方法*/    public static NotifyService getNotifyService(){        return new NotifyServiceByWeixinImpl();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其它类不变,但xml会发现有很大差别:

<bean id="order" class="twm.spring.start.Order">    <constructor-arg name="username" value="张老三"></constructor-arg>    <constructor-arg name="notifyservice1" ref="notify2"></constructor-arg>    <constructor-arg name="orderno" value="1234567"></constructor-arg></bean><bean id="notify2" class="twm.spring.start.NotifyFactory"    factory-method="getNotifyService" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意看指向的class并不是NotifyService的实现类,而是指向静态工厂NotifyFactory,并且配置factory-method="getNotifyService"指定调用哪个工厂方法:

静态工厂方法需要参数,怎么传递? 
文档上告诉我们静态工厂方法的参数,应该通过constructor-arg元素产生,就像是bean的构造函数一样

四、实例工厂的方法注入

实例工厂的意思是获取对象实例的方法不是静态的,所以需要首先new工厂类,再调用普通的实例方法::

public class NotifyFactory {    /*普通工厂方法*/    public NotifyService getNotifyService(){        return new NotifyServiceByWeixinImpl();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

实例工厂方法(非静态)和静态工厂方法本质相同(除了使用facory-bean属性替代class属性,其他都相同),因此细节就不讨论了。

<bean id="order" class="twm.spring.start.Order">    <constructor-arg name="username" value="张老三"></constructor-arg>    <constructor-arg name="notifyservice1" ref="notify2"></constructor-arg>    <constructor-arg name="orderno" value="1234567"></constructor-arg></bean><bean id="notifyfactory" class="twm.spring.start.NotifyFactory" /><bean id="notify2" factory-bean="notifyfactory" factory-method="getNotifyService" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Spring IOC注入方式用得最多的是1、2两种。

现在常用的注解注入不属于xml配置注入方式,故后面开篇单讲

附录: 
1、给属性设置空格字符串(“”)

<bean class="ExampleBean">    <property name="email" value=""/></bean>
  • 1
  • 2
  • 3

上面的配置相当于exampleBean.setEmail("")

2、给属性设置null值

<bean class="ExampleBean">    <property name="email">        <null/>    </property></bean>
  • 1
  • 2
  • 3
  • 4
  • 5

上面配置相当于exampleBean.setEmail(null)

恭喜你,看完这里,基本可以应付日常开发了。

本文博客地址:http://blog.csdn.net/soonfly/article/details/68507615 (转载请注明出处)

原创粉丝点击