(❤重点)Spring02_基于xml的IOC

第三章 使用 spring 的 IOC解决程序耦合

使用spring已将帮我们集成好的环境降低程序的耦合度:

3.1 准备 spring 的 的 开发包

  • 官网:
  • 下载地址:
    • [http://repo.springsource.org/libs-release-local/org/springframework/spring](http://repo.springsource.org/libs-release-

3.2 Spring基于XML文件的IOC环境搭建和入门

(1)在xml文件中配置好

  • 创建配置配置文件bean.xml

    • 先导入Spring的约束(在官网上找)

      <?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">
      </beans>
      
    • 在配置文件中创建好要加载的service和dao接口的实现类对象的配置

      <?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">
          <!-- 把对象的创建交给spring来管理-->
          <!-- id是唯一标准,在以后的方法中要想创建该对象可以使用该id-->
          <!-- class 是指向service或者dao的实现类  的全限定类名-->
          <bean id="accountService" class="com.zy.service.impl.AccountServiceImpl" />
          <bean id="accountDao"  class="com.zy.dao.Impl.AccountDaoImpl" />	
      </beans>	
      
      • 在标签中包含
      • 每一个标签来指定一个series或者dao的实现类
        • 标签有id和class两个属性
        • id属性: 是唯一标准,在以后的方法中要想创建该对象可以使用该id
        • class属性: 是指向service或者dao的实现类 的全限定类名
  • 和2.1.3中配置bean.properties文件一样,只不过在配置该xml,spring会识别改xml文件,调用spring的容器方法会自动生成该对象

(2)怎么使用配置好的xml文件??

  • 还是结合上面那个案例:

    • 在series业务层中调用dao持久层的对象:

      //账户的业务成实现类:业务成接口的实现类
      public class AccountServiceImpl implements IAccountService {
         //1 获取核心容器对象(核心容器ApplicationContext有三个实现类)
         //在这里我们用的是ClassPathXmlApplicationContext实现类
         //在构造方法中传入一个bean.xml配置文件的路径
         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
         //2 根据在bean.xml配置中的id获取bean对象,使用getBean()方法
         IAccountDao iAccountDao = (IAccountDao)applicationContext.getBean("accountDao");
         public void saveAccount(Account account) {
            iAccountDao.saveAccount(account);
         }
      }
      
  • 在ui表现层调用业务层的对象:

      //模拟一个表现层,用于调用业务层
      public class Client {
         public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
            IAccountService iAccountService = (IAccountService) applicationContext.getBean("accountService");
            System.out.println(iAccountService);
            iAccountService.saveAccount(new Account());
         }
      }
    

3.3 ApplicationContext容器接口的三个实现类

  • ClassPathXmlApplicationContext实现类
    • 他可以加载类路径下的配置文件
    • 要求配置文件必须在类路径下,不在类路径下加载不了。
    • 在构造函数的形参中传入一个配置文件的全限定类名
  • FileSystemXmlApplicationContext实现类 -------- 用的较少
    • 他可以加载磁盘任意路径下的配置文件(必须有访问权限)
    • 在构造函数的形参中传入一个 路径
  • AnnotationConfigApplicationContext实现类
    • 他是读取注解创建容器的,是后面的内容

在这里插入图片描述

3.4核心容器的两个接口引发出来的问题

  • 两个核心容器接口:
    • ApplicationContext接口
    • BeanFactory接口
  • ApplicationContext接口 -------在开发中更多的是采用此接口定义容器对象
    • 他在构建核心容器的时,构建对象采取的策略是 立即加载的方式
    • 立即加载方式:只要一读取完bean.xml配置文件,马上创建出配置文件中配置的对象
    • 当执行完 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");的时候,配置文件中的对象都被创建出来放到容器中了
    • 该接口的三个实现类在3.1.3已经说明了
    • 单例对象适应
  • BeanFactory接口
    • BeanFactory 才是 Spring 容器中的顶层接口,ApplicationContext 是它的子接口。
    • 他在构建核心容器的时,构建对象采取的策略是 延迟加载的方式
    • 延迟加载的方式:什么时候根据id获取对象了,什么时候才会真正的去创建对象
    • 当执行完beanFactor.getBean("accountService");方法的时候,该对象才会被创建出来放到容器中
    • 该接口也有很多的实现类,其中一个实现类是XmlBeanFactory(已经过时)构造方法中传入一个Resource对象(new ClassPathResource("bean.xml")
    • 多例对象适应

3.5 spring对Bean的管理细节

(1)创建Bean对象的三种方式

  1. 使用默认的构造函数创建对象,并存入spring容器中
    • 如何配置,使在spring的IOC创建该对象的时候,使用构造函数创建???

      • 在配置文件中使用bean标签,配置id和class属性之后,其没有其他属性和标签的时(在后面使用其他标签或者属性来使用其他的构造函数)默认调用class指向类的构造方法

      • 如果创建的对象没有默认构造函数,该对象无法创建

      • <!-- 方式1 使用默认构建函数 -->
        <!-- id是唯一标准,在以后的方法中要想创建该对象可以使用该id-->
        <!-- class 要使用什么类中的方法来创建该对象-->
        <!-- 调用class指向类的默认构造方法创建-->
        <bean id="accountService" class="com.zy.service.impl.AccountServiceImpl" />
        
  2. 通过某个类的方法创建(普通工厂中的方法创建对象)一个对象,并存入spring容器中
    • 如何配置,使在spring的IOC创建该对象的时候,使用其他类的一个方法创建对象???

      • 在bean标签中,id还是唯一标志,class不在需要指定,其次在添加 factory-bean属性指向实例化工厂类的id,根据该类的id找到该类在工厂中的对象,在通过factory-method 属性找到对象具体的方法,创建出class指定的类

      • factory-bean 属性:用于指定实例工厂 bean 的 id。

      • factory-method 属性:用于指定实例工厂中创建对象的方法。

      • <!-- 此种方式是:
            	调用InstanceFactory实现类中的createAccountService方法创建AccountService对象
                先把工厂的创建交给 spring 来管理。
                然后在使用工厂的 bean 来调用里面的方法
                factory-bean 属性:用于指定实例工厂 bean 的 id。
                factory-method 属性:用于指定实例工厂中创建对象的方法。
        -->
        <!-- 在工厂中创建InstanceFactory实现类,通过instancFactory该id调用工厂中创建好的id-->
        <bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
        <!-- 通过该id来调用容器中的方法的时候,先通过bean工厂对象factory-bean的id找到工厂中创建好的对象,在通过factory-method调用指定的方法-->
        <bean id="accountService" factory-bean="instancFactory" factory-method="createAccountService"></bean>
        
  3. 使用工厂中的静态方法(某个类中的静态方法)创建对象,,并存入spring容器中
    • 如何配置,使在spring的IOC创建该对象的时候,使用其他类的一个静态方法创建对象???

      • 在bean标签中,id还是唯一标志,其次在添加class属性指定为静态工厂的全限定类名,factory-method属性指定静态方法名

      • 注意:class属性此处指定的是 静态方法的类 ,class属性指向的是要调用哪个类的方法,而不是要创建什么实现类(应为在工厂中都是Object类型)

      • factory-method 属性:用于指定实例工厂中创建对象的静态方法。

      • <!-- 此种方式是:
               使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器
                id 属性:指定 bean 的 id,用于从容器中获取
                class 属性:指定静态工厂的全限定类名
                factory-method 属性:指定生产对象的静态方法
         -->
        <bean id="accountService"  class="com.itheima.factory.StaticFactory" factory-method="createAccountService"></bean>
        

(2)bean标签的总结及bean对象的作用范围(scope属性):

  • bean标签的作用:

    • 用于配置对象让 spring 来创建的
    • 默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功
  • bean标签的属性:

    • id属性:给对象在容器中提供一个唯一标识。用于获取对象。

    • class属性:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数,要调用该类中的方法

    • factory-bean 属性:用于指定实例工厂 bean 的 id,调用该bean对象

    • factory-method 属性:用于指定实例工厂中创建对象的方法。

    • init-method 属性:创建该方法的时候,执行什么方法

    • destroy-method 属性: 销毁该方法的时候,执行什么方法

    • scope属性 :指定对象的作用范围。

      • 取值:

        • singleton :默认值,单例的.
        • prototype :多例的.
        • request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.(作用在web应用的请求范围)
        • session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.(作用在web应用的会话范围)
        • global_session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session.(用作于集群环境的会话范围(全局会话范围),如果没有集群环境(只有一个服务器),他就是session)
          • 在这里插入图片描述
          • 当没有服务器集群(只有一个服务器 ),global_session就session
          • 当有服务器集群的时候,各个服务器的session实现共享,就是global_session

(3) Bean对象的生命周期

  • 单利对象和多例对象的生命周期不一样
  • 单例对象: scope="singleton" 单例对象就是立即创建容器对象
    • 一个应用只有一个对象的实例。它的作用范围就是整个引用
    • 生命周期:
      • 出生时间:当应用加载(bean.xml文件被解析),创建容器时,对象就被创建了
      • 存活时间:只要容器在,对象一直活着
      • 死亡时间:当应用卸载,销毁容器时,对象就被销毁了
    • 总结:单例对象的生命周期和容器的生命周期相同
  • 多例对象:scope="prototype" 多例对象就是延迟创建容器对象
    • 每次访问对象时,都会重新创建对象实例。
    • 生命周期:
      • 出生时间:当使用对象时(applicationContext.getBean(“accountDao3”)),创建新的对象实例
      • 存活时间:只要对象在使用中,就一直活着
      • 死亡时间:当对象长时间不用时,被 java 的垃圾回收器回收了。
    • 总结:和普通对象一样,长时间不用,被垃圾回收机制销毁

3.6 spring 的依赖注入

(1) 什么是依赖注入:

​ Dependency Injection。它是 spring 框架核心 ioc 的具体实现。IOC的作用是降低程序之间的依赖关系(在当前类中需要用到其他类的对象),各个类之间的依赖关系以后都交给spring来维护,我们只需要在配置文件中说明配置什么样的对象,告诉spring是在创建该对象的时候要传入的参数,就叫做依赖的注入

​ (调用本类的其他构造函数或者set方法构造本类的一个对象)

(2)依赖注入能注入的数据有三类:

  • 基本类型和String类型
  • 其他的Bean类型(在配置文件或者在注解配置过的Bean)
  • 复杂类型 / 集合类型

(3) 注入的方式有三种:

  • 第一种:使用构造函数提供
  • 第二种:使用set方法提供
  • 第三种:使用注解提供(在后面讲注解的时候,在讲)
  • 第四种:使用p标签重命名

(4)使用构造函数注入:

  • 需要使用的标签(在bean标签内部使用):

    • constructor-arg标签:
      • 常用属性:
        • type属性:指定参数在构造函数中的数据类型(不常用)
        • index属性:指定参数在构造函数参数列表的索引位置(不常用)
        • name属性:指定参数在构造函数中的名称 (常用)
        • value属性:指定对于形参传入的值,它能赋的值是基本数据类型和 String 类型(常用)
        • ref 属性:指向其他Bean对象id,它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
  • 优势:

    • 可以在创建对象的时候,进行属性的注入,调用不同的构造方法
  • 弊端:

    • 根据传入的值来构建不同的构造方法,前体是要有这个构造方法
    • 对于不同的传参,需要各自各样的构造方法
  • 案例:

    • 要Bean对象:User

      • public class User {
           //两个普通的类型
           private String name;
           private int sex;
           //一个实体类类型
           private Date date;
           public User() {
           }
         	public void setName(String name) {
        		this.name = name;
        	}
        
        	public void setSex(int sex) {
        		this.sex = sex;
        	}
        
        	public void setDate(Date date) {
        		this.date = date;
        	}
        
        	public String getName() {
        		return name;
        	}
        
           @Override
           public String toString() {
              return "User{" +
                    "name='" + name + '\'' +
                    ", sex=" + sex +
                    ", date=" + date +
                    '}';
           }
        }
        
    • 容器配置文件:

      • <bean id="date" class="java.util.Date"/>
        <!--通过构造函数来创建user对象-->
        <bean id="user_0" class="com.zy.domain.User"/>
        
        <!-- 构造函数注入(传递三个参数的构造函数) -->
        <bean id="user_1" class="com.zy.domain.User">
            <constructor-arg name="name" value="zhangsan"/>
            <constructor-arg name="sex" value="18"/>
            <constructor-arg name="date" ref="date"/>
        </bean>
        <!-- 在配置文件加载的时候,容器中会有两个User对象,一个是通过默认构造函数构造,一个是使用其他的构造函数构造-->
        

(5)使用set方法注入:

  • 涉及到的标签:

    • property标签(在bean标签内部使用)
      • 常见属性:
        • name属性:用于指定注入时所调用的set方法名称
        • value属性:指定对于形参传入的值,它能赋的值是基本数据类型和 String 类型(常用)
        • ref 属性:指向其他Bean对象id,它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
  • 优点:不用各样的构造方法,使用set方法进行赋值

  • 注意:在name属性的时候,set方法去掉set,在把第一个字母改为小写

  • 案例:

    •     <!--set方式注入-->
          <bean id="user_2" class="com.zy.domain.User">
             <property name="name" value="张阳"/>
              <property name="date" ref="date"/>
          </bean>
      

(6) 注入集合数据:

  • 采用set的方法给类的每一个属性进行赋值

  • 使用到的标签:

    • <list> <array> <set> <map> <props>
      • 用于给List结构的集合注入的标签: <list> <array> <set>
      • 用于给Map结构的集合注入的标签:<map> <props>
      • 总结:结构相同,标签可以互换
    • 这些标签常见的属性:
      • 在<list> <array> <set>,直接写多个<value>,value标签内部写值
      • <map> 使用 <entry key="map的键" value="map的值"/> 或者 <entry key="map的键"><value>map的值</value></entry>
      • <props> 标签中,使用 <prop key="键">值</prop>
  • 案例:

    • 要容器中创建的Bean对象:

      • public class User2 {
           private String[] strings;
           private List<String> list;
           private Set<String> set;
           private Map<String, String> map;
           private Properties properties;
        
           public User2() {
           }
        
           public void setStrings(String[] strings) {
              this.strings = strings;
           }
        
           public void setList(List<String> list) {
              this.list = list;
           }
        
           public void setSet(Set<String> set) {
              this.set = set;
           }
        
           public void setMap(Map<String, String> map) {
              this.map = map;
           }
        
           public void setProperties(Properties properties) {
              this.properties = properties;
           }
        
           @Override
           public String toString() {
              return "User2{" +
                    "strings=" + Arrays.toString(strings) +
                    ", list=" + list +
                    ", set=" + set +
                    ", map=" + map +
                    ", properties=" + properties +
                    '}';
           }
        }
        
    • 配置文件:

      • <bean id="user_3" class="com.zy.domain.User2">
            <property name="list">
                <list>
                    <value>aaa</value>
                    <value>bbb</value>
                    <value>ccc</value>
                </list>
            </property>
        
            <property name="strings">
                <list>
                    <value>123</value>
                    <value>456</value>
                    <value>789</value>
                </list>
            </property>
        
            <property name="set">
                <set>
                    <value>987</value>
                    <value>876</value>
                    <value>765</value>
                </set>
            </property>
        
            <property name="map">
                <map>
                    <entry key="abc" value="123"/>
                    <entry key="bcd"><value>456</value></entry>
                </map>
            </property>
        
            <property name="properties">
                <props>
                    <prop key="zzz">111</prop>
                    <prop key="FFF">222</prop>
                    <prop key="ddd">333</prop>
                </props>
            </property>
        </bean>
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小镇男孩~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值