spring05----DI的配置使用

Posted Hermioner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring05----DI的配置使用相关的知识,希望对你有一定的参考价值。

一. 依赖和依赖注入的基本概念

1. 类之间的关系

传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系
泛化:表示类与类之间的继承关系、接口与接口之间的继承关系;
实现:表示类对接口的实现;
依赖:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种“相识 关系”,只在某个特定地方(比如某个方法体内)才有关系。
关联:表示类与类或类与接口之间的依赖关系,表现为“拥有关系”;具体到代码可以用实例变量来表示;
聚合:属于是关联的特殊情况,体现部分-整体关系,是一种弱拥有关系;整体和部分可以有不一样的生命周期;是 一种弱关联;
组合:属于是关联的特殊情况,也体现了体现部分-整体关系,是一种强“拥有关系”;整体与部分有相同的生命周 期,是一种强关联;
Spring IoC容器的依赖有两层含义:Bean依赖容器和容器注入Bean的依赖资源:
Bean依赖容器:也就是说Bean要依赖于容器,这里的依赖是指容器负责创建Bean并管理Bean的生命周期,正是由 于由容器来控制创建Bean并注入依赖,也就是控制权被反转了,这也正是IoC名字的由来,此处的有依赖是指Bean和 容器之间的依赖关系。
容器注入Bean的依赖资源:容器负责注入Bean的依赖资源,依赖资源可以是Bean、外部文件、常量数据等,在 Java中都反映为对象,并且由容器负责组装Bean之间的依赖关系,此处的依赖是指Bean之间的依赖关系,可以认为是 传统类与类之间的“关联”、“聚合”、“组合”关系。

2. 为什么要引入DI?

动态替换Bean依赖对象,程序更灵活:替换Bean依赖对象,无需修改源文件:应用依赖注入后,由于可以采用配置 文件方式实现,从而能随时动态的替换Bean的依赖对象,无需修改java源文件;
更好实践面向接口编程,代码更清晰:在Bean中只需指定依赖对象的接口,接口定义依赖对象完成的功能,通过容 器注入依赖实现;
更好实践优先使用对象组合,而不是类继承:因为IoC容器采用注入依赖,也就是组合对象,从而更好的实践对象组合

  • 采用对象组合,Bean的功能可能由几个依赖Bean的功能组合而成,其Bean本身可能只提供少许功能或根本无任何功能,全部委托给依赖

           Bean,对象组合具有动态性,能更方便的替换掉依赖Bean,从而改变Bean功能;

  • 而如果采用类继承,Bean没有依赖Bean,而是采用继承方式添加新功能,,而且功能是在编译时就确定了,不具有动态性,而且采用类继

          承导致Bean与子Bean之间高度耦合,难以复用。

增加Bean可复用性:依赖于对象组合,Bean更可复用且复用更简单;
降低Bean之间耦合:由于我们完全采用面向接口编程,在代码中没有直接引用Bean依赖实现,全部引用接口,而且 不会出现显示的创建依赖对象代码,而且这些依赖是由容器来注入,很容易替换依赖实现类,从而降低Bean与依赖之间 耦合;
代码结构更清晰:要应用依赖注入,代码结构要按照规约方式进行书写,从而更好的应用一些最佳实践,因此代码 结构更清晰。

二. 依赖注入的方式

1. 构造器注入

构造器注入可以根据参数索引注入、参数类型注入或Spring3支持的参数名注入(但参数名注入是有限制的,个人觉得好麻烦啊,因此只介绍前两种)

(1)根据参数索引注入

使用标签“<constructor-arg index="1"  value="1"/>"来指定注入的依赖,其中index表示索引,从0开始,即第一个参数索引为0,value来指定注入的常量值,配置方式如下:

<constructor-arg index="0"  value="Hello World!"/>

(2)根据参数类型注入

使用标签“ <constructor-arg type="java.lang.String"  value="Hello World!"/>” 来指定注入的依赖,其中“type”表示需要匹配的参数类型,可以是基本类型也可以是其它类型,如“int”、“java.lang.String”、“value”来指定注入的常量值,配置方式如下:

(3)举例:

<!-- 通过构造器参数索引方式依赖注入 -->
    <bean id="byIndex" class="com.test.spring.HelloImpl2">
       <constructor-arg index="0" value="Hello World"></constructor-arg>
       <constructor-arg index="1" value="2"></constructor-arg>
    </bean>
    <!-- 通过构造器参数类型方式依赖注入 -->
    <bean id="byName" class="com.test.spring.HelloImpl2">
       <constructor-arg type="java.lang.String" value="Hello Spring"></constructor-arg>
       <constructor-arg type="int" value="3"></constructor-arg>
    </bean>
 1 public class HelloImpl2 implements HelloApi{
 2     private String message;
 3     private int a;
 4     public HelloImpl2(String message,int a) {
 5         this.message=message;
 6         this.a=a;
 7     }
 8     public void sayHello() {
 9         System.out.println(message+": "+a);
10     }
11 }
View Code
 1 public class HelloTest {
 2     public static void main(String args[]) {
 3         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 4         HelloImpl2 aHelloImpl2=(HelloImpl2) context.getBean("byIndex");
 5         aHelloImpl2.sayHello();
 6         
 7         HelloImpl2 bHelloImpl2=(HelloImpl2) context.getBean("byName");
 8         bHelloImpl2.sayHello();
 9     }
10         
11 }
12 
13 Hello World: 2
14 Hello Spring: 3
View Code

2. 静态工厂注入

<bean id="bystaticFactory" class="com.test.spring.HelloApiStaticFactory" factory-method="newInstance">
        <constructor-arg index="0" value="haha"></constructor-arg>
        <constructor-arg index="1" value="3"></constructor-arg>
    </bean>
 1 public class HelloApiStaticFactory {
 2     //工厂方法
 3     public static HelloApi newInstance(String message,int a) {
 4         //返回需要的Bean实例
 5         return new HelloImpl2(message,a);
 6     }
 7 
 8 }
 9 
10 
11 public class HelloImpl2 implements HelloApi{
12     private String message;
13     private int a;
14     public HelloImpl2(String message,int a) {
15         this.message=message;
16         this.a=a;
17     }
18     public void sayHello() {
19         System.out.println(message+": "+a);
20     }
21 }
View Code
 1 public class HelloTest {
 2     public static void main(String args[]) {
 3         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 4         HelloImpl2 aHelloImpl2=(HelloImpl2) context.getBean("bystaticFactory");
 5         aHelloImpl2.sayHello();
 6         
 7     }
 8         
 9 }
10 
11 
12 haha: 3
View Code

3. 实例工厂类

<bean id="byinstanceFactory" factory-bean="instanceFactory" factory-method="newInstance">
        <constructor-arg index="0" value="haha"></constructor-arg>
        <constructor-arg index="1" value="3"></constructor-arg>
    </bean>
    
    <bean id="instanceFactory" class="com.test.spring.HelloApiInstanceFactory"></bean>
 1 public class HelloApiInstanceFactory {
 2     public HelloApi newInstance(String message,int a) {
 3         return new HelloImpl2(message,a);
 4     }
 5 
 6 }
 7 
 8 public class HelloImpl2 implements HelloApi{
 9     private String message;
10     private int a;
11     public HelloImpl2(String message,int a) {
12         this.message=message;
13         this.a=a;
14     }
15     public void sayHello() {
16         System.out.println(message+": "+a);
17     }
18 }
View Code
 1 public class HelloTest {
 2     public static void main(String args[]) {
 3         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 4         HelloImpl2 aHelloImpl2=(HelloImpl2) context.getBean("byinstanceFactory");
 5         aHelloImpl2.sayHello();
 6         
 7     }
 8         
 9 }
10 
11 haha: 3
View Code

4. setter注入

setter注入,是通过在通过构造器、静态工厂或实例工厂实例好Bean后,通过调用Bean类的setter方法进行注入依赖。setter注入方式只有一种根据setter名字进行注入。如下:

<bean id="bySetter" class="com.test.spring.HelloImpl2">
        <property name="message" value="Hello World!"></property>
        <property name="a" value="3"></property>
    </bean>
 1 public class HelloImpl2 implements HelloApi{
 2     private String message;
 3     private int a;
 4     public void setMessage(String message) {
 5         this.message = message;
 6     }
 7     public void setA(int a) {
 8         this.a = a;
 9     }
10     public void sayHello() {
11         System.out.println(message+": "+a);
12     }
13     
14 }
View Code
 1 public class HelloTest {
 2     public static void main(String args[]) {
 3         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 4         HelloImpl2 aHelloImpl2=(HelloImpl2) context.getBean("bySetter");
 5         aHelloImpl2.sayHello();
 6         
 7     }
 8         
 9 }
10 
11 
12 Hello World!: 3
View Code

note: setter注入的方法名要遵循“ JavaBean getter/setter 方法名约定”:

JavaBean:是本质就是一个POJO类,但具有一下限制:
该类必须要有公共的无参构造器,如public HelloImpl4() {};
属性为private访问级别,不建议public,如private String message;
属性必要时通过一组setter(修改器)和getter(访问器)方法来访问;
setter方法,以“set” 开头,后跟首字母大写的属性名,如“setMesssage”,简单属性一般只有一个方法参 数,方法返回值通常为“void”;
getter方法,一般属性以“get”开头,对于boolean类型一般以“is”开头,后跟首字母大写的属性名,如 “getMesssage”,“isOk”;

  还有一些其他特殊情况,比如属性有连续两个大写字母开头,如“URL”,则setter/getter方法为:“setURL” 和“getURL”,其他一些特殊情况请参看“Java Bean”命名规范。

5. 注入常量

注入常量是依赖注入中最简单的。配置方式如下所示:

 <property name="message" value="Hello World!"/>

注意此处“value”中指定的全是字符串,由Spring容器将此字符串转换成属性所需要的类型,如果转换出错,将抛出相应的异常。

Spring容器目前能对各种基本类型把配置的String参数转换为需要的类型。

注:Spring类型转换系统对于boolean类型进行了容错处理,除了可以使用“true/false”标准的Java值进行注入,还 能使用“yes/no”、“on/off”、“1/0”来代表“真/假”,所以大家在学习或工作中遇到这种类似问题不要觉得是人 家配置错了,而是Spring容错做的非常好。

6. 注入Bean ID(???)

7. 注入集合类型

包括Collection类型、Set类型、List类型

(1)List类型:需要使用<List>标签来配置注入,具体配置如下:

  • 可选的“value-type”属性,表示列表中条目的数据的类型,默认是String类型。
  • 也可以采用发行来代替具体的类型,比如 value-type="java.util.List<String>"
<bean id="listBean" class="com.test.spring.ListBean">
        <property name="values">
            <list value-type="int">
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
    </bean>
 1 public class ListBean {
 2     private List values;
 3 
 4     public List getValues() {
 5         return values;
 6     }
 7 
 8     public void setValues(List values) {
 9         this.values = values;
10     }
11 
12 }
View Code
 1 public class HelloTest {
 2     public static void main(String args[]) {
 3         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 4         ListBean listBean=(ListBean) context.getBean("listBean");
 5         System.out.println(listBean.getValues().get(1));
 6         System.out.println(listBean.getValues().get(1).getClass());
 7     }
 8         
 9 }
10 
11 
12 2
13 class java.lang.Integer
View Code

(2)set类型:需要使用<set>标签来配置注入。其配置参数和<list>完全一样。

8. 注入数组类型

需要使用<array>标签来配置注入,其中标签属性“value-type”和“merge”和<list>标签含义 完全一样,具体配置如下:

<bean id="arrayBean" class="com.test.spring.ArrayBean">
        <property name="array">
            <array value-type="int">
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </array>
        </property>
    </bean>
 1 public class ArrayBean {
 2     private int array[];
 3 
 4     public int[] getArray() {
 5         return array;
 6     }
 7 
 8     public void setArray(int[] array) {
 9         this.array = array;
10     }
11     
12 
13 }
14 
15 
16 public class HelloTest {
17     public static void main(String args[]) {
18         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
19         ArrayBean arrayBean=(ArrayBean) context.getBean("arrayBean");
20         System.out.println(arrayBean.getArray()[1]);
21         
22     }
23         
24 }
25 
26 
27 2
View Code

note:也可以注入二维数组:

9. 注入字典(Map)类型

需要使用<map>标签来配置注入,,其属性 “key-type”和“value-type”分别指定“键”和“值”的数据类型,其含义和<list>标签的“value-type”含义一 样,在此就不罗嗦了,并使用<key>子标签来指定键数据,<value>子标签来指定键对应的值数据,具体配置如下

 

<bean id="mapBean" class="com.test.spring.MapBean">
      <property name="values">
           <map key-type="java.lang.String" value-type="java.lang.Integer">
            <entry key="hello" value="23"></entry>
        </map>
      </property>        
    </bean>
 1 public class MapBean {
 2     private Map<String, Integer> values;
 3 
 4     public Map<String, Integer> getValues() {
 5         return values;
 6     }
 7 
 8     public void setValues(Map<String, Integer> values) {
 9         this.values = values;
10     }
11     
12 
13 }
View Code
 1 public class HelloTest {
 2     public static void main(String args[]) {
 3         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 4         MapBean mapBean=(MapBean) context.getBean("mapBean");
 5         System.out.println(mapBean.getValues().get("hello"));
 6     }
 7         
 8 }
 9 
10 23
View Code

10. Properties注入

Spring能注入java.util.Properties类型数据,需要使用<props>标签来配置注入,键和值类型必 须是String,不能变,子标签<prop key=”键”>值</prop>来指定键值对,具体配置如下

<bean id="propertiesBean" class="com.test.spring.PropertiesBean">
         <property name="values">
             <props value-type="int" merge="default">   <!-- 虽然指定了value-type,但实际上该属性不起作用,因为Properties的key和value必须都是String类型 -->
                 <prop key="1">a</prop>
                 <prop key="2">b</prop>
             </props>
         </property>
    </bean>
 1 public class PropertiesBean {
 2     private Properties values;
 3 
 4     public Properties getValues() {
 5         return values;
 6     }
 7 
 8     public void setValues(Properties values) {
 9         this.values = values;
10     }
11     
12 
13 }
View Code
 1 public class HelloTest {
 2     public static void main(String args[]) {
 3         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 4         PropertiesBean propertiesBean=(PropertiesBean) context.getBean("propertiesBean");
 5         System.out.println(propertiesBean.getValues());
 6     }
 7         
 8 }
 9 
10 {2=b, 1=a}
View Code

11. 注入Bean之间的关系(注入依赖Bean)

 可以有两种方式,一种是通过构造函数,另外一种是通过setter方式来注入依赖的Bean

“<constructor-arg index="0" value="Hello World!"/>”和“<property name="message" value="Hello World!"/>”中的value属性替换成bean属性,其中bean属性指定配置文件中的其 他Bean的id或别名。另一种是把<value>标签替换为<.ref bean=”beanName”>

(1)构造参数方式注入依赖的Bean

<ref="beanName">----只可以是这种

    <bean id="di" class="com.test.spring.HelloImpl2">
    </bean>
    <!-- 通过过构造器注入 -->
    <bean id="bean1" class="com.test.spring.HelloApiDecorator">
        <constructor-arg index="0" ref="di"/>
    </bean>

(2)setter方式注入依赖的Bean

<.ref bean=”beanName”>---只可以是这种

   <!-- 通过构造器注入 -->
    <bean id="bean2" class="com.test.spring.HelloApiDecorator">
         <property name="helloApi">
             <ref bean="di"/>
         </property>
    </bean>

(3)举例

<!-- 定义依赖Bean -->
    <bean id="di" class="com.test.spring.HelloImpl2">
    </bean>
    <!-- 通过过构造器注入 -->
    <bean id="bean1" class="com.test.spring.HelloApiDecorator">
        <constructor-arg index="0" ref="di"/>
    </bean>
    
    <!-- 通过构造器注入 -->
    <bean id="bean2" class="com.test.spring.HelloApiDecorator">
         <property name="helloApi">
             <ref bean="di"/>
         </property>
    </bean>
 1 public interface HelloApi {
 2     public void sayHello();
 3 
 4 }
 5 
 6 
 7 public class HelloImpl2 implements HelloApi{
 8     public void sayHello() {
 9         System.out.println("hello");
10     }
11     
12 }
13 
14 
15 public class HelloApiDecorator implements HelloApi{
16     private HelloApi helloApi;
17     public HelloApiDecorator() {
18         
19     }
20     public HelloApiDecorator(HelloApi helloApi) {
21         this.helloApi=helloApi;
22     }
23     public void sayHello() {
24         System.out.println("before decorator");
25         helloApi.sayHello();
26         System.out.println("after decorator");
27     }
28     public void setHelloApi(HelloApi helloApi) {
29         this.helloApi = helloApi;
30     }
31     
32 
33 }
View Code
 1 public class HelloTest {
 2     public static void main(String args[]) {
 3         ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
 4         //通过构造器方式注入
 5         HelloApi helloApi=(HelloApi) context.getBean("bean1");
 6         helloApi.sayHello();
 7         //通过setter方法注入
 8         HelloApi helloApi2=(HelloApi) context.getBean("bean2");
 9         helloApi2.sayHello();
10     }
11         
12 }
13 
14 
15 before decorator
16 hello
17 after decorator
18 before decorator
19 hello
20 after decorator
View Code

12. 内部定义Bean

内部Bean就是在<property>或<constructor-arg>内通过<bean>标签定义的Bean,该Bean不管是否指定id或 name,该Bean都会有唯一的匿名标识符,而且不能指定别名,该内部Bean对其他外部Bean不可见,具体配置如下

<bean id="bean1" class="com.test.spring.HelloApiDecorator">
        <property name="helloApi">
            <bean id="bean2" class="com.test.spring.HelloImpl2"/>
        </property>
</bean>