Spring框架的IoC容器

Spring框架的IoC容器

Spring框架的IoC容器

Spring框架的核心
Spring框架实现控制反转功能的容器

  • IoC容器负责创建装配需要注入到容器中实现控制反转的对象
  • IoC容器还负责管理 容器中的对象 的整个生命周期,被IoC管理的对象通常被称为Bean
  • IoC容器对应于Spring框架的BeanFactory接口,描述了管理对象的工厂
    • BeanFactory接口中定义了从容器中获取对象的方法
    • 而通常IoC的容器对象是BeanFactory的子接口ApplicationContext的实例对象,以此作为Bean容器
      • ApplicationContext接口继承了其父接口BeanFactory的所有功能
      • ApplicationContext接口还提供了国际化支持、资源访问等方法
  • Spring中,可使用xml文件进行Bean对象的配置,也可使用注解配置
    • 通常Spring配置文件的名字为:applicationContext.xmlbeans.xml

使用Spring的IoC容器

  • 涉及的jar包有:
    1. org.springframework.beans.jar
    2. org.springframework.context.jar
    3. org.springframework.context.support.jar
    4. org.springframework.core.jar
    5. org.springframework.expression.jar
    6. commons-logging.jar用于日志输出,便于调试,并非Spring框架中的依赖jar
  • ApplicationContext接口的常用实现类
    1. FileSystemXmlApplicationContext
      • 该类通过xml配置文件的完整物理路径创建IoC容器
    2. ClassPathXmlApplicationContext
      • 该类通过从类路径下的xml配置文件创建IoC容器
    3. WebXmlApplicationContext
      • 该类适用于Web应用程序中,可以配合Servlet容器进行工作,通过在Web根目录下的xml配置文件创建IoC容器

xml配置

配置文件主要配置需要在IoC容器中进行控制反转的Java Bean对象
通常需给出以下信息:

类名
bean的作用范围(单例原型
bean的依赖关系

  • xml配置文件的根元素是<beans>
    根元素配置如下;
    <?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>
    
  • <bean>元素是根元素<beans>的子元素
    • id属性:用来唯一标识一个bean
    • name属性:定义bean的别名,可以使用空格分号隔开的多个别名
    • class属性:必须指定的属性,指定用来创建bean对象的完全限定类名
      • Spring容器默认使用类的无参构造函数创建对象,且默认是使用单例的
        • 即:放入容器的对象必须要有一个无参的构造函数,或者完全没有构造函数
          <bean>元素配置如下;
        <bean id="productService" class="com.Spring.demo.service.ProductServiceImpl"/></bean>
        

使用IoC容器

  1. 创建IoC容器
    • 通过从类路径下的xml配置文件创建IoC容器
      示例如下;
      ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
      
    • 通过xml配置文件的完整物理路径创建IoC容器
      示例如下;
      ApplicationContext context = new FileSystemXmlApplicationContext("D:\\文档资料夹\\文件夹\\idea_ws\\Spring_demo\\src\\ApplicationContext.xml");
      
  2. IoC容器中得到bean
    • 通过beanidname获得
      示例如下;
      ProductService service = (ProductService) context.getBean("productService");
      
    • 通过bean实现的接口类型获得
      • Spring中通过面向接口编程实现分层解耦
      • 先定义接口,规范接口中要实现的功能和方法
      • 再创建接口的具体实现类
        示例如下;
      ProductService productService = context.getBean(ProductService.class);
      
    • 通过beanname和接口类型获得
      示例如下;
      ProductService productService = context.getBean("productService",ProductService.class);
      
  3. 关闭IoC容器
    • 通过ApplicationContext接口的实现类的close()方法关闭
      示例如下;
((ClassPathXmlApplicationContext)context).close();

Bean的配置

bean对象的创建、销毁等都可交由IoC容器管理

scope属性:用来配置bean的作用范围
  • scope="singleton" : 单例模式bean 默认情况下容器创建时被实例化,并被缓存下来
    • scope的默认值为singleton
    • 被缓存下来的bean对象在后续所有请求到来时被IoC容器返回
    • 可以在<bean>元素中配置lazy-init="true"实现延迟初始化
      • 默认的lazy-init属性为false,即:非延迟初始化(容器创建时被实例化
        • 延迟初始化 : 当第一次需要获取bean对象时实例化
        • 对所有bean对象进行延迟初始化,可以在根元素<beans>元素中配置default-lazy-init="true"来实现
  • scope="prASototype" : 原型模式bean对象每次从容器中获取时都返回的是另外一个重新实例化的对象
bean注入值
  1. 构造函数注入
    • 使用时的条件是注入的bean对象有定义对应的构造器
    • 构造函数注入的方式:
      • 使用构造函数中的形参名注入:
        • 使用<constructor-arg>元素进行构造函数中的形参名注入
        • <constructor-arg>元素中使用name属性指定形参名
        • 注入形参值的方式:
          • 使用<constructor-arg>元素的value属性进行形参值的注入
          • 也可以使用<constructor-arg>元素的子元素<value>进行形参值的注入
          • 虽然可以有两种注入方式,但此两种注入方式不可同时使用
        • 对象引用注入:
          • 若构造函数的形参中含有自定义类型,即:传递的是一个对象的引用
            • 可以使用<constructor-arg>元素的ref属性进行对象引用的注入
              • ref属性值为对应的bean对象的id属性值
            • 使用<constructor-arg>元素的子元素<ref>进行注入bean对象的引用
              • <ref>元素的bean属性值为对应的bean对象的id属性值
            • 与上相同,<ref>元素与ref属性不可同时存在
              示例如下:
      <bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" lazy-init="false">
          <constructor-arg name="id" value="25"/>
          <constructor-arg name="value">
              <value>Rv</value>
          </constructor-arg>
          <constructor-arg name="productDao">
              <ref bean="productDao"></ref>
          </constructor-arg>
      </bean>
      <bean id="productDao" class="com.Spring.demo.dao.ProductDaoIml"></bean>
      
      • 使用构造函数中的索引下标注入:
        示例如下:
      <bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" lazy-init="false">
        <constructor-arg index="0" value="25"/>
        <constructor-arg index="1" value="Rv"/>
        <constructor-arg index="2">
             <ref bean="productDao"/>
        </constructor-arg>
      </bean>
      <bean id="productDao" class="com.Spring.demo.dao.ProductDaoIml"></bean>
      
  2. 属性注入(setter方法注入)
    • 使用<bean>元素的子元素<property>进行属性注入
    • 使用<property>元素的name属性指定注入属性的属性名
    • 属性值的注入与构造函数中形参值的注入时相同
      • 属性值的注入既可以通过<property>元素的子元素<value>注入
      • 也可以通过<property>元素的value属性注入
      • <property>元素的子元素<value>value属性不可同时用于同一个<property>元素
      • 当属性为一个自定义类的对象时,可使用ref属性或<ref>子元素
      • 当需要给一个属性对象的引用值设为null值时
        • 可以使用<property>元素的子元素<null/>进行注入
          示例如下:
      <bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" lazy-init="false">
          <property name="id" value="25"/>
          <property name="value">
              <value>98984984</value>
          </property>
          <property name="productDao" ref="productDao"/>
          <property name="productDao1">
              <ref bean="productDao"/>
          </property>
      </bean>
      
    • 注入集合对象
      1. Set类型
      • 可以在<property>元素的子元素<set>中定义
      • <set>元素中使用其子元素<value>定义集合中的每一个元素的值
        示例如下:
      <property name="userlist">
          <set>
              <value>张三</value>
              <value>李四</value>
          </set>
      </property>
      
      1. List类型
      • 可以在<property>元素的子元素<list>中定义
      • set类型相同,使用<list>元素的子元素<value>定义集合元素
        示例如下:
      <property name="products">
          <list>
              <value>手机</value>
              <value>路由器</value>
          </list>
      </property>
      
      1. Map类型
      • 可以在<property>元素的子元素<map>中定义
      • 可以使用<map>元素的子元素<entry>定义Map集合中的键值对元素
      • 使用<entry>元素的key属性指定Map集合键值对元素的
      • 使用<entry>元素的value属性指定Map集合键值对元素的
        示例如下:
      <property name="users">
          <map>
              <entry key="zhangsan" value="ID00001"/>
              <entry key="lisi" value="ID00002"/>
          </map>
      </property>
      
      • 其他键值对集合
        • 使用<props>元素也可以定义键值对集合
        • 使用<props>元素的子元素<prop>元素定义键值对集合的键值对元素
        • <prop>元素的key属性上定义键值对元素的
        • <prop>元素里面就可以定义键值对元素的
          示例如下:
        <property name="user">
            <props>
                <prop key="zhangsan">ID00001</prop>
                <prop key="lisi">ID00001</prop>
            </props>
        </property>
        
    • 注入数组对象
      • <property>元素下使用其子元素<array>定义要注入的数组
      • <array>元素中使用其子元素<value>定义数组中的元素
        示例如下:
        <property name="id">
            <array>
                <value>01</value>
                <value>02</value>
            </array>
        </property>
        
依赖注入(DI
  • 方式一:引用已定义的bean
    • 构造器注入属性注入中注入bean对象就是引用的已定义的bean对象
  • 方式二:使用内部bean
    • 使用嵌套的<bean>元素进行注入
    • 嵌套的<bean>元素注入的bean对象仅适用于当前注入的属性
    • 其他的属性无法引用已经嵌套的<bean>元素注入的bean对象
      • 因为嵌套的<bean>元素注入的bean对象并没有id属性
      • 若其他地方在已有嵌套同一个bean对象时,再使用引用注入,则该对象并非单例
        示例如下:
      <constructor-arg name="productDao">
          <bean class="com.Spring.demo.dao.ProductDaoIml"/>
      </constructor-arg>
      
bean的生命周期
  1. 通过实现接口完成bean对象的生命周期
  • 初始化方法
    • 实现InitializingBean接口
    • InitializingBean接口中定义了afterPropertiesSet()方法
    • afterPropertiesSet()方法在设置了所有属性后自动调用
  • 销毁方法
    • 实现DisposableBean接口
    • DisposableBean接口中定义了destroy()方法
    • destroy()方法在关闭IoC容器时自动调用
      示例如下:
package com.Spring.demo.dao;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import javax.sql.DataSource;

public class BaseDao implements InitializingBean, DisposableBean {
    private DataSource dataSource;

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /**
    * InitializingBean 接口中定义的初始化方法
    * @throws Exception
    */
    @Override
    public void afterPropertiesSet() throws Exception {
        ······
    }

    /**
    * DisposableBean 接口中定义的销毁方法
    * @throws Exception
    */
    @Override
    public void destroy() throws Exception {
        ······
    }
}

  1. 通过xml配置文件指定
  • 使用xml配置文件中的<bean>元素的init-method属性指定初始化方法
  • 使用xml配置文件中的<bean>元素的destroy-method属性指定销毁方法
  • 在使用init-methoddestroy-method属性时,属性值应该是bean对象当中的方法名
    示例如下:
<bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" init-method="initMethod" destroy-method="destroyMethod" lazy-init="false">
      <property name="productDao" ref="productDao"/>
</bean>
  • 如果bean对象不是单例的,即是原型
    • 初始化方法在bean对象每次被获取时执行,销毁方法不执行,bean对象的销毁由JVM进行垃圾回收,不由IoC容器管理
    • 也就是说只有在bean对象是单例的时候销毁方法才被执行
  • 如果既实现了InitializingBean接口,又使用了init-method属性,则优先执行afterPropertiesSet()方法,再调用init-method属性指定的方法
  • 如果既实现了DisposableBean接口,又使用了destroy-method属性,则优先执行destroy()方法,再调用destroy-method属性指定的方法
自动装配
  • 使用<bean>元素的autowire属性指定自动装配模式
  • autowire属性值有:byNamebyType
    byNamebyType
    通过bean对象名字自动装配通过bean对象类型自动装配
  • 根据setter方法进行自动装配
    • IoC容器根据setter方法后面的名称将首字母小写在容器中找对应id值的bean对象进行自动装配
    • 由于自动装配根据的是bean对象对应的<bean>元素的id属性值,所以id属性值必须是唯一的
    • IoC容器根据setter方法的形参类型在IoC容器中找对应的bean对象进行自动装配
    • IoC容器中存在多个相同类型的bean对象,则IoC容器报错不能唯一确定注入的对象
      示例如下:
<bean id="productService" class="com.Spring.demo.service.ProductServiceImpl" autowire="byName" lazy-init="false">
    <property name="id" value="25"/>
    <property name="value" value="98984984"/>
</bean>
IoC容器管理数据源
  • 导入与数据源相关的jar包,例如:commons-dbcp-1.4.jar、commons-pool-1.6.jar以及数据库的驱动jar
  • Spring的配置文件applicationContext.xml中使用<beans>根元素的子元素<bean>元素注入数据源到IoC容器,交由IoC容器管理
  • 数据源bean对象的id属性可设为DataSource
  • 数据源对象使用commons-dbcp.jar中的BasicDataSource的实例对象
  • 由于数据源交由IoC容器管理,故此在关闭IoC容器时就要先关闭数据源
    • 使用<bean>元素的destroy-method属性指定关闭数据源的方法为close
  • 使用属性注入的方式对数据源的各种属性进行配置注入
    属性说明
    driverClassName数据库驱动类类名
    url数据库连接地址
    username数据库的登录用户名
    password数据库的登录密码
    maxActive最大连接数
    maxIdle最大空闲连接数
    maxWait最大等待时间
    initialSize初始连接数
    defaultAutoCommit是否自动提交事务
  • 在使用属性注入数据源的属性配置时,可使用属性配置文件的方式
    • 在使用属性配置文件时,需要先引入context的命名空间
      命名空间的引用示例:
      <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
      
    • 使用<context:property-placeholder>元素引入属性占位符
      • <context:property-placeholder>元素的location属性指定属性配文件的位置
        • 使用classpath:表示类路径
        • 使用classpath*:表示类路径以及类路径下的子路径
      • <context:property-placeholder>元素的ignore-unresolvable属性表示不可解析的属性是否被忽略
      • 实质上是创建了一个bean对象,在其他bean对象被属性注入前校验有无${···}表达式,若有则进行替换
    • .properties属性配置文件中以键值对的形式存储属性以及属性值
    • 在xml文件中使用${key}获取属性配置文件中key对应的值,然后赋给value属性
  • 将数据源注入到需要连接数据库的bean对象中
    示例如下:
    Spring配置文件applicationContext.xml:
<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
<bean id="DataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db.driver}"/>
    <property name="url" value="${db.url}"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
    <property name="maxActive" value="10"/>
    <property name="maxIdle" value="2"/>
    <property name="maxWait" value="4000"/>
    <property name="initialSize" value="1"/>
    <property name="defaultAutoCommit" value="false"/>
</bean>
<bean id="productDao" class="com.Spring.demo.dao.ProductDaoIml">
    <property name="dataSource" ref="DataSource"/>
</bean>

属性配置文件db.properties

db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/store?useSSL=false

在Web应用中使用Spring

Web应用程序的IoC容器是WebApplicationContext接口的实例对象

  • Spring启动时在/WEB/INF下的web.xml中加载Spring的监听器并通过监听器加载Spring的配置文件创建IoC容器
  • Spring监听器的配置
    • 由于Spring的监听器类在org.springframework.web.jar定义,所以需先导入该jar
    • web.xml中的根元素<web-app>下配置<listener>元素用以配置监听器类
    • 监听器类包含在<listener-class>元素中,而<listener-class>元素是<listener>的子元素
    • Spring的监听器通过加载解析Spring的配置文件来创建IoC容器,故而需使用<context-param>元素指定Spring的配置文件位置
    • <context-param>元素的子元素<param-name>标识上下文参数的名字。即该参数名表示Spring的配置文件的加载路径
    • <context-param>元素的子元素<param-value>包含了Spring配置文件的具体路径
      • 路径中可使用classpath:classpath*:来表示
        表达式含义
        classpath:表示当前类路径下
        classpath*:表示当前类路径下以及类路径的子路径
      • 如果Spring的配置文件位于WEB-INF目录下,则示例如下:
        <param-value>/WEB-INF/spring-config.xml</param-value>
        示例如下:
    <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:spring-config.xml</param-value>
    </context-param>
    <listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
  • Spring的监听器会创建WebApplicationContext接口的实例对象并保存在ServletContext
  • 获取IoC容器
    • 可使用WebApplicationContextUtils工具类的getWebApplicationContext(..)方法获取SpringIoC容器
      示例如下:
    package com.Spring.web.servlet;
    
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    
    import javax.servlet.http.HttpServlet;
    
    public class BaseServlet extends HttpServlet {
        public <T> T getService(String ServiceName,Class<T> ServiceType){
            WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(super.getServletContext());
            return context.getBean(ServiceName,ServiceType);
        }
    }
    
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值