学习spring容器IOC之依赖和依赖注入

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习spring容器IOC之依赖和依赖注入相关的知识,希望对你有一定的参考价值。

学习开涛跟我学spring3

http://jinnianshilongnian.iteye.com/

为什么要应用依赖注入,应用依赖注入能给我们带来哪些好处呢?

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

? 采用对象组合,Bean的功能可能由几个依赖Bean的功能组合而成,其Bean本身可能只提供少许功能或根本无任何功能,全部委托给依赖
Bean,对象组合具有动态性,能更方便的替换掉依赖Bean,从而改变Bean功能;
? 而如果采用类继承,Bean没有依赖Bean,而是采用继承方式添加新功能,,而且功能是在编译时就确定了,不具有动态性,而且采用类继
承导致Bean与子Bean之间高度耦合,难以复用。

3.1代码结构如下

技术分享

 

3.1构造器注入

HelloImpl代码如下
package com.springframe.springstudy.chapter3;

import com.springframe.springstudy.HelloApi;

public class HelloImpl implements HelloApi {

    private  String message;
    private  int index;

    public HelloImpl(String message, int index) {
        this.message = message;
        this.index = index;
    }

    public HelloImpl(){

    }

    @Override
    public void sayHello() {
        System.out.printf("helloImpl1:(message:"+this.message+",index:"+this.index+")");
    }
}

helloword.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="byIndex" class="com.springframe.springstudy.chapter3.HelloImpl">
        <constructor-arg index="0" value="Hello World!"/>
        <constructor-arg index="1" value="1"/>
    </bean>
    <!-- 通过构造器参数类型方式依赖注入-->
    <bean id="byType" class="com.springframe.springstudy.chapter3.HelloImpl">
        <constructor-arg type="java.lang.String" value="Hello World!"/>
        <constructor-arg type="int" value="2"/>
    </bean>
    <!-- 通过构造器参数名称方式依赖注入-->
    <bean id="byName" class="com.springframe.springstudy.chapter3.HelloImpl">
        <constructor-arg name="message" value="Hello World!"/>
        <constructor-arg name="index" value="3"/>
    </bean>
</beans>
HelloImplTest测试代码如下
package com.springframe.springstudy.chapter3;

import com.springframe.springstudy.HelloApi;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@SpringBootTest
public class HelloImplTest {

    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("chapter3/helloword.xml");
        HelloApi index = context.getBean("byIndex", HelloApi.class);
        HelloApi type = context.getBean("byType", HelloApi.class);
        HelloApi name = context.getBean("byName", HelloApi.class);
        index.sayHello();
        type.sayHello();
        name.sayHello();
    }
}

测试结果如下:

技术分享

 

 3.2讲解

1.、根据参数索引注入,使用标签

<constructor-arg index="1" value="1"/> ,index值1,代码构造器参数的索引位置(从0开始),value代表需要注入的值.

2.根据参数类型进行注入,使用标签

<constructor-arg type="int" value="2"/>,type的值代表参数的类型,value代表需要注入的值
3.根据参数名进行注入,使用标签“<constructor-arg name="message" value="Hello World!"/>”来指定注入

的依赖,其中“name”表示需要匹配的参数名字,“value”来指定注入的常量值,

3.3使用静态工厂注入

在HelloImpl加上以下代码

public static HelloApi newInstance(String message,int index){
        return new HelloImpl(message,index);
    }

在helloword.xml加上以下代码

 <!-- 通过 静态工厂 构造器参数索引方式依赖注入-->
    <bean id="byIndexFactory" class="com.springframe.springstudy.chapter3.HelloImpl" factory-method="newInstance">
        <constructor-arg index="0" value="Hello World!  byIndexFactory"/>
        <constructor-arg index="1" value="1"/>
    </bean>

然后进行测试

 @Test
    public void testFactory() {
        ApplicationContext context = new ClassPathXmlApplicationContext("chapter3/helloword.xml");
        HelloApi indexFactory = context.getBean("byIndexFactory", HelloApi.class);
        indexFactory.sayHello();
    }

3.4通过setter方法注入

在helloword.xml加上以下代码(需要在HelloImpl中未index,message,写入setter方法)

 <!-- 通过 setter 构造器参数索引方式依赖注入-->
    <bean id="byIndexSetter" class="com.springframe.springstudy.chapter3.HelloImpl" >
       <property name="index" value="2"/>
        <property name="message" value="Hello World!  setter"/>
    </bean>

进行测试

@Test
    public void testSetter() {
        ApplicationContext context = new ClassPathXmlApplicationContext("chapter3/helloword.xml");
        HelloApi indexFactory = context.getBean("byIndexSetter", HelloApi.class);
        indexFactory.sayHello();
    }

3.5 注入集合、数组和字典

Spring不仅能注入简单类型数据,还能注入集合(Collection、无序集合Set、有序集合List)类型、数组(Array)类
型、字典(Map)类型数据、Properties类型数据

1、注入集合类型:包括Collection类型、Set类型、List类型数据

  集合list注入:

HelloImpl代码
package com.springframe.springstudy.chapter3;

import com.springframe.springstudy.HelloApi;

import java.util.Arrays;
import java.util.List;

public class HelloImpl implements HelloApi {

    private  String message;
    private  int index;

    private List<String> list;

    public HelloImpl(String message, int index) {
        this.message = message;
        this.index = index;
    }

    public HelloImpl(){

    }

    public static HelloApi newInstance(String message,int index){
        return new HelloImpl(message,index);
    }

    @Override
    public void sayHello() {
        System.out.println("helloImpl1:(message:"+this.message+",index:"+this.index+",list:"+ this.list+")");
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public void setList(List<String> list) {
        this.list = list;
    }
}

helloword.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="byIndex" class="com.springframe.springstudy.chapter3.HelloImpl">
        <constructor-arg index="0" value="Hello World!"/>
        <constructor-arg index="1" value="1"/>
    </bean>
    <!-- 通过构造器参数类型方式依赖注入-->
    <bean id="byType" class="com.springframe.springstudy.chapter3.HelloImpl">
        <constructor-arg type="java.lang.String" value="Hello World!"/>
        <constructor-arg type="int" value="2"/>
    </bean>
    <!-- 通过构造器参数名称方式依赖注入-->
    <bean id="byName" class="com.springframe.springstudy.chapter3.HelloImpl">
        <constructor-arg name="message" value="Hello World!"/>
        <constructor-arg name="index" value="3"/>
    </bean>
    <!-- 通过 静态工厂 构造器参数索引方式依赖注入-->
    <bean id="byIndexFactory" class="com.springframe.springstudy.chapter3.HelloImpl" factory-method="newInstance">
        <constructor-arg index="0" value="Hello World!  byIndexFactory"/>
        <constructor-arg index="1" value="1"/>
    </bean>
    <!-- 通过 setter 构造器参数索引方式依赖注入-->
    <bean id="byIndexSetter" class="com.springframe.springstudy.chapter3.HelloImpl">
        <property name="index" value="2"/>
        <property name="message" value="Hello World!  setter"/>
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
    </bean>
</beans>

测试代码

 @Test
    public void testSetter() {
        ApplicationContext context = new ClassPathXmlApplicationContext("chapter3/helloword.xml");
        HelloApi indexFactory = context.getBean("byIndexSetter", HelloApi.class);
        indexFactory.sayHello();
    }

测试结果

技术分享

set类型(HelloImpl类中加入属性:

private Collection<String> values;并写入对应的setter方法

)

 <!-- 通过 setter 构造器参数索引方式依赖注入-->
    <bean id="byIndexSetter" class="com.springframe.springstudy.chapter3.HelloImpl">
        <property name="index" value="2"/>
        <property name="message" value="Hello World!  setter"/>
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <property name="values">
            <set>
                <value>a</value>
                <value>b</value>
                <value>c</value>
            </set>
        </property>
    </bean>

2.注入数组

 HelloImpl配置属性:private String[] array;并对应的setter方法

   <!-- 通过 setter 构造器参数索引方式依赖注入-->
    <bean id="byIndexSetter" class="com.springframe.springstudy.chapter3.HelloImpl">
        <property name="index" value="2"/>
        <property name="message" value="Hello World!  setter"/>
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <property name="values">
            <set>
                <value>a</value>
                <value>b</value>
                <value>c</value>
            </set>
        </property>
        <property name="array">
            <array>
                <value>array1</value>
                <value>array2</value>
            </array>
        </property>
    </bean>

3.map注入

 <!-- 通过 setter 构造器参数索引方式依赖注入-->
    <bean id="byIndexSetter" class="com.springframe.springstudy.chapter3.HelloImpl">
        <property name="index" value="2"/>
        <property name="message" value="Hello World!  setter"/>
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <property name="values">
            <set>
                <value>a</value>
                <value>b</value>
                <value>c</value>
            </set>
        </property>
        <property name="array">
            <array>
                <value>array1</value>
                <value>array2</value>
            </array>
        </property>
        <property name="map">
            <map>
                <entry>
                    <key><value>1</value></key>
                    <value>1</value>
                </entry>
                <entry>
                    <key><value>2</value></key>
                    <value>2</value>
                </entry>
            </map>
        </property>
    </bean>

4.properties注入

  <!-- 通过 setter 构造器参数索引方式依赖注入-->
    <bean id="byIndexSetter" class="com.springframe.springstudy.chapter3.HelloImpl">
        <property name="index" value="2"/>
        <property name="message" value="Hello World!  setter"/>
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <property name="values">
            <set>
                <value>a</value>
                <value>b</value>
                <value>c</value>
            </set>
        </property>
        <property name="array">
            <array>
                <value>array1</value>
                <value>array2</value>
            </array>
        </property>
        <property name="map">
            <map>
                <entry>
                    <key><value>1</value></key>
                    <value>1</value>
                </entry>
                <entry>
                    <key><value>2</value></key>
                    <value>2</value>
                </entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="key">key</prop>
                <prop key="key1">key1</prop>
            </props>
        </property>
    </bean>

5.引用其他的bean

用ref 标签

 <bean name="test" class="java.lang.String">
        <constructor-arg index="0" value="1111"/>
    </bean>
    <!-- 通过 setter 构造器参数索引方式依赖注入-->
    <bean id="byIndexSetter" class="com.springframe.springstudy.chapter3.HelloImpl">
        <property name="index" value="2"/>
        <property name="message" value="Hello World!  setter"/>
        <property name="list">
            <list>
               <ref bean="test"/>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
        <property name="values">
            <set>
                <value>a</value>
                <value>b</value>
                <value>c</value>
            </set>
        </property>
        <property name="array">
            <array>
                <value>array1</value>
                <value>array2</value>
            </array>
        </property>
        <property name="map">
            <map>
                <entry>
                    <key><value>1</value></key>
                    <value>1</value>
                </entry>
                <entry>
                    <key><value>2</value></key>
                    <value>2</value>
                </entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="key">key</prop>
                <prop key="key1">key1</prop>
            </props>
        </property>
    </bean>

6.注入null值

  <property name="properties"><null></null>
        </property>

一、构造器注入:
1)常量值
简写:<constructor-arg index="0" value="常量"/>
全写:<constructor-arg index="0"><value>常量</value></constructor-arg>
2)引用
简写:<constructor-arg index="0" ref="引用"/>
全写:<constructor-arg index="0"><ref bean="引用"/></constructor-arg>
二、setter注入:
1)常量值
简写:<property name="message" value="常量"/>
全写:<property name="message"><value>常量</value></ property>
2)引用
简写:<property name="message" ref="引用"/>
全写:<property name="message"><ref bean="引用"/></ property>
3)数组:<array>没有简写形式
4)列表:<list>没有简写形式
5)集合:<set>没有简写形式
6)字典
简写:<map>
<entry key="键常量" value="值常量"/>
<entry key-ref="键引用" value-ref="值引用"/>
</map>
全写:<map>
<entry><key><value>键常量</value></key><value>值常量</value></entry>
http://jinnianshilongnian.iteye.com 1.4 【第三章】 DI 之 3.1 DI的配置使用 ——跟我学spring3
第 62 / 366 页
<entry><key><ref bean="键引用"/></key><ref bean="值引用"/></entry>
</map>
7)Properties:没有简写形式

延迟初始化Bean

延迟初始化也叫做惰性初始化,指不提前初始化Bean,而是只有在真正使用时才创建及初始化Bean。
配置方式很简单只需在<bean>标签上指定 “lazy-init” 属性值为“true”即可延迟初始化Bean。
Spring容器会在创建容器时提前初始化“singleton”作用域的Bean,“singleton”就是单例的意思即整个容器
每个Bean只有一个实例,后边会详细介绍。Spring容器预先初始化Bean通常能帮助我们提前发现配置错误,所以如果
没有什么情况建议开启,除非有某个Bean可能需要加载很大资源,而且很可能在整个应用程序生命周期中很可能使用不
到,可以设置为延迟初始化。
延迟初始化的Bean通常会在第一次使用时被初始化;或者在被非延迟初始化Bean作为依赖对象注入时在会随着初
始化该Bean时被初始化,因为在这时使用了延迟初始化Bean。
容器管理初始化Bean消除了编程实现延迟初始化,完全由容器控制,只需在需要延迟初始化的Bean定义上配置即
可,比编程方式更简单,而且是无侵入代码的。

<bean id="helloApi"
 class="cn.javass.spring.chapter2.helloworld.HelloImpl"
 lazy-init="true"/>

使用depends-on

depends-on是指指定Bean初始化及销毁时的顺序,使用depends-on属性指定的Bean要先初始化完毕后才初始
化当前Bean,由于只有“singleton”Bean能被Spring管理销毁,所以当指定的Bean都是“singleton”时,使用
depends-on属性指定的Bean要在指定的Bean之后销毁。

<bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>
<bean id="decorator"
 class="cn.javass.spring.chapter3.bean.HelloApiDecorator"
depends-on="helloApi">
<property name="helloApi"><ref bean="helloApi"/></property>
</bean>

那“depends-on”有什么好处呢?主要是给出明确的初始化及销毁顺序,比如要初始化“decorator”时要确保
“helloApi”Bean的资源准备好了,否则使用“decorator”时会看不到准备的资源;而在销毁时要先在
“decorator”Bean的把对“helloApi”资源的引用释放掉才能销毁“helloApi”,否则可能销毁 “helloApi”时而
“decorator”还保持着资源访问,造成资源不能释放或释放错误

自动装配

自动装配就是指由Spring来自动地注入依赖对象,无需人工参与。
目前Spring3.0支持“no”、“byName ”、“byType”、“constructor”四种自动装配,默认是“no”指不支
持自动装配的,其中Spring3.0已不推荐使用之前版本的“autodetect”自动装配,推荐使用Java 5+支持的
(@Autowired)注解方式代替;如果想支持“autodetect”自动装配,请将schema改为“spring-beans-2.5.xsd”
或去掉。
自动装配的好处是减少构造器注入和setter注入配置,减少配置文件的长度。自动装配通过配置<bean>标签的
“autowire”属性来改变自动装配方式。接下来让我们挨着看下配置的含义。
一、default:表示使用默认的自动装配,默认的自动装配需要在<beans>标签中使用default-autowire属性指
定,其支持“no”、“byName ”、“byType”、“constructor”四种自动装配,如果需要覆盖默认自动装配

基本的作用域

一、singleton:指“singleton”作用域的Bean只会在每个Spring IoC容器中存在一个实例,而且其完整生命
周期完全由Spring容器管理。对于所有获取该Bean的操作Spring容器将只返回同一个Bean。

























































以上是关于学习spring容器IOC之依赖和依赖注入的主要内容,如果未能解决你的问题,请参考以下文章

spring源码解析之IOC容器——依赖注入

spring ioc容器之Bean实例化和依赖注入

spring技术内幕读书笔记之IoC容器的学习

Spring之IOC容器

spring 之 DI

spring之IOC