Spring:基于xml文件的控制反转(ioc)

1、环境搭建

导入spring使用最基本的坐标

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

在resources下创建一个applicationContext.xml文件,配置所需对象的ioc 。

通常一个类对应一个bean标签,指定【唯一id标识】和【全类名】。

<?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">
    
    <!--将创建某个service对象的控制权交给框架-->
    <bean id="accountService" class="com.service.impl.AccountServiceImpl"/>
</beans>

 一旦配置了ioc,就会将对应的对象存入ioc容器中。ioc是一个键值对结构的容器,key值就是唯一id标识,value值就是通过全类名反射创建的对象。所以,通过唯一标识就可以定位到对应的对象。

底层创建Bean对象的三种设计方式

  • 第一种:【使用默认构造函数创建】。在spring的配置文件中,使用bean标签,且除了id和class属性外没有其他属性时,使用的就是该种方式。此时如果Bean类中没有默认构造函数,将无法创建对象。(基本上每个类都会有默认的构造方法)
  • 第二种:【根据某个类中的方法来获取返回值对象】,比如在某个A类中有一个方法,该方法会返回一个B类对象,如何获取B类对象?可以通过id创建A类对象再调用方法获取B类对象。但是如果想要直接通过id获取B类对象呢?要进行如下配置:
<!--配置通过某个类中的方法获取对象-->
<bean id="nameA" class="cao.zhanpeng.factory.FactoryDemo" />
<bean id="accountService" factory-bean="nameA" factory-method="getAccountService"/>
  • 第三种:使用某个类中的静态方法来创建对象
<!--配置通过某个类中的静态方法获取对象-->
<bean id="accountService" class="com.factory.FactoryDemo" factory-method="getAccountService"/>

bean对象的作用范围

bean标签默认是配置使用【单例模式】创建bean对象的。可以通过scope属性来调整bean对象的作用范围,该属性有5种取值,常用的是前两种:

  • singleton,默认值,表示单例的。
  • prototype,多例模式。
  • request,作用于web应用的请求范围。
  • session,作用于web应用的会话范围。
  • global-session,作用于集群环境的会话范围(全局会话范围),当不是集群环境时,和session一样。

bean对象的生命周期

单例对象

  • 出生:容器创建时出生
  • 存活:容器在,对象在
  • 死亡:容器销毁(容器实现类对象.close()),对象销毁。

多例对象

  • 出生:使用对象时出生
  • 存活:对象只要在使用过程中就一直存活
  • 死亡:spring无法识别是否要使用对象,只有当对象长时间不用,且没有别的对象引用时,由java垃圾回收器回收。

2、获取ioc中的对象

先获取ioc容器,再根据唯一id定位到相应的对象。

//获取核心容器对象ioc
ApplicationContext ca = new ClassPathXmlApplicationContext("applicationContext.xml");
//根据id获取对象的第一种方式,返回的是一个Object对象,需要强转一下
AccountService accountService1 = (AccountService) ca.getBean("accountService");
System.out.println(accountService1);//com.service.impl.AccountServiceImpl@6f45df59
//根据id获取对象的第二种方式,不需要强转
AccountService accountService2 = ca.getBean("accountService", AccountService.class);
System.out.println(accountService2);//com.service.impl.AccountServiceImpl@6f45df59

ApplicationContext对象的实现类

常用的有三个:

  • ClassPathXmlApplicationContext,可以加载类路径下的配置文件,用得较多。
  • FileSystemXmlApplicationContext,可以加载磁盘任意路径下的配置文件(前提是有访问权限),传递的是文件路径。
  • AnnotationConfigApplicationContext,用于读取注解创建容器的。

ApplicationContext接口和BeanFactory接口的区别

  • ApplicationContext接口是BeanFactory接口的子类接口
  • ApplicationContext对象在创建核心容器时,采用的是立即加载的方式,只要一读取完配置文件,马上就创建文件中配置的对象。单例对象适用。用得较多。
  • BeanFactory采取的是延迟加载的方式,什么时候根据id获取对象了,什么时候才真正地创建。多例对象适用。
  • spring会通过识别单例还是多例来选择是立即加载还是延迟加载。单例就是立即加载;多例就是延迟加载。

3、依赖注入

构造函数注入

通过构造函数注入其实就是底层通过构造函数来给成员变量赋值。使用的是bean标签下的constructor-arg标签,该标签有5个属性

  • 三个用来确定是哪一个参数的,一次只能存在一种
    • 通过类型确定参数type,比如=java.lang.String,这种方式在有多个同类型参数时无法进行区分。
    • 通过索引来确定参数index,索引从0开始,这种方式也不太灵活。
    • 通过参数名称来确定参数name,这种方式可以唯一确定且更灵活。
  • 一个用来为基本类型和String类型注入值的属性value,虽然配置的属性值都是字符串,但是spring可以将基本类型的字符串自动转成对应的基本类型。
  • 一个用来引用Bean对象类型的属性ref,值=配置过的Bean对象的唯一id值。
<!--配置依赖注入-->
<bean id="accountService" class="cao.zhanpeng.service.impl.AccountServiceImpl">
    <constructor-arg name="username" value="张三"></constructor-arg>
    <constructor-arg name="age" value="25"></constructor-arg>
    <constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>

<!--配置日期对象的引用-->
<bean id="now" class="java.util.Date"></bean>

在创建bean对象时,注入数据是必须的操作,否则无法创建对象。

通过构造函数来注入有一个弊端,就是如果参数列表中有不需要的数据,也得注入。

set方法注入

相当于使用set方法为成员变量赋值。类中需要有对应变量的set方法(get方法随意)使用的是bean标签下的property标签,该标签有三个属性:

  • name,指定对应set方法的属性名。
  • value,同上。
  • ref,同上。
<!--配置set方法依赖注入-->
<bean id="accountService" class="cao.zhanpeng.service.impl.AccountServiceImpl">
    <property name="username" value="张三"></property>
    <property name="age" value="25"></property>
    <property name="birthday" ref="now"></property>
</bean>

<!--配置日期对象的引用-->
<bean id="now" class="java.util.Date"></bean>

注入复杂类型数据

数组,可以看做是单列集合

单列集合

  • List
  • Set

双列集合

  • Map
  • Properties
<!--配置set方法对复杂类型进行依赖注入-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
    <!--数组-->
    <property name="str">
        <array>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </array>
    </property>
    
    <!--List集合-->
    <property name="list">
        <list>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </list>
    </property>

    <!--Set集合-->
    <property name="set">
        <set>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </set>
    </property>

    <!--Map集合-->
    <property name="map">
        <map>
            <entry key="aaa" value="AAA"></entry>
            <entry key="bbb">
                <value>BBB</value>
            </entry>
        </map>
    </property>

    <!--properties集合-->
    <property name="prop">
        <props>
            <prop key="aaa">AAA</prop>
            <prop key="bbb">BBB</prop>
        </props>
    </property>
</bean>

 注意

  • 数组、List集合和Set集合的标签是可以通用的。
  • 双列集合之间的标签也是可以通用的,但是要注意map对应entry,props对应prop。
  • entry键值对有两种写法。
发布了70 篇原创文章 · 获赞 1 · 访问量 2258

猜你喜欢

转载自blog.csdn.net/caozp913/article/details/103774190
今日推荐