Java_Spring:3. IoC 的概念和作用-程序的耦合和解耦

本文详细介绍了Java Spring框架中的IoC(Inversion of Control)概念及其作用,通过XML配置文件展示了如何实现依赖注入,包括BeanFactory和ApplicationContext的区别、bean的定义与作用范围,以及不同方式的实例化。此外,还讨论了构造函数和set方法注入的使用。
摘要由CSDN通过智能技术生成

目录

1 案例的前期准备

1.1 准备 spring 的开发包

1.2 创建业务层接口和实现类

1.3 创建持久层接口和实现类

2 基于 XML 的配置

2.1 第一步:拷贝必备的 jar 包到工程的 lib 目录中

2.2 第二步:在类的根路径下创建一个任意名称的 xml 文件(不能是中文)

2.3 第三步:让 spring 管理资源,在配置文件中配置 service 和 dao​​​​​​​

2.4 测试配置是否成功

3 Spring 基于 XML 的 IOC 细节

3.1 spring 中工厂的类结构图

3.1.1 BeanFactory 和 ApplicationContext 的区别

3.1.2 ApplicationContext 接口的实现类

3.2 IOC 中 bean 标签和管理对象细节

3.2.1 bean 标签

3.2.2 bean 的作用范围和生命周期

3.2.3 实例化 Bean 的三种方式 

3.3 spring 的依赖注入

3.3.1 依赖注入的概念

3.3.2 构造函数注入

3.3.3 set 方法注入

3.3.4 使用 p 名称空间注入数据(本质还是调用 set 方法)

3.3.5 注入集合属性

4 Spring 配置文件中提示的配置


  • 1 案例的前期准备

    • 案例:账户的业务层和持久层的依赖关系解决。
    • 1.1 准备 spring 的开发包

    • 1.2 创建业务层接口和实现类

      • /**
            * 账户的业务层接口
            * @Version 1.0
        */
        public interface IAccountService {
            /**
            * 保存账户(此处只是模拟,并不是真的要保存)
            */
            void saveAccount();
        }
        
        /**
        * 账户的业务层实现类
        * @Version 1.0
        */
        public class AccountServiceImpl implements IAccountService {
            private IAccountDao accountDao = new AccountDaoImpl();//此处的依赖关系有待解决
            
            @Override
            public void saveAccount() {
                accountDao.saveAccount();
            }
        }
    • 1.3 创建持久层接口和实现类

      • /**
        * 账户的持久层接口
        * @Version 1.0
        */
        public interface IAccountDao {
            /**
            * 保存账户
            */
            void saveAccount();
        }
        
        /**
        * 账户的持久层实现类
        * @Version 1.0
        */
        public class AccountDaoImpl implements IAccountDao {
            @Override
            public void saveAccount() {
                System.out.println("保存了账户");
            }
        }
  • 2 基于 XML 的配置

    • 2.1 第一步:拷贝必备的 jar 包到工程的 lib 目录中

      • ​​​​​​​
    • 2.2 第二步:在类的根路径下创建一个任意名称的 xml 文件(不能是中文)

      • ​​​​​​​
      • 给配置文件导入约束:
        • /spring-framework-5.0.2.RELEASE/docs/spring-framework-reference/html5/core.html
    • 2.3 第三步:让 spring 管理资源,在配置文件中配置 service 和 dao​​​​​​​

      • <!-- bean 标签:用于配置让 spring 创建对象,并且存入 ioc 容器之中
                 id 属性:对象的唯一标识。
                 class 属性:指定要创建对象的全限定类名
        -->
        <!-- 配置 service --> 
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
        <!-- 配置 dao -->
        <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
    • 2.4 测试配置是否成功

      • /**
         * 模拟一个表现层
         * @Version 1.0
        */
        public class Client {
            /**
             * 使用 main 方法获取容器测试执行
        
            */
            public static void main(String[] args) {
                //1.使用 ApplicationContext 接口,就是在获取 spring 容器
                ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
            
                //2.根据 bean 的 id 获取对象
                IAccountService aService = (IAccountService) ac.getBean("accountService");
                System.out.println(aService);
        
                IAccountDao aDao = (IAccountDao) ac.getBean("accountDao");
                System.out.println(aDao);
            }
        }
      • 运行结果:
  • 3 Spring 基于 XML 的 IOC 细节

    • 3.1 spring 中工厂的类结构图

      • 3.1.1 BeanFactory 和 ApplicationContext 的区别

        • BeanFactory 才是 Spring 容器中的顶层接口。
        • ApplicationContext 是它的子接口。
        • BeanFactory 和 ApplicationContext 的区别:
          • 创建对象的时间点不一样。
          • ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
          • BeanFactory:什么使用什么时候创建对象。
      • 3.1.2 ApplicationContext 接口的实现类

        • ClassPathXmlApplicationContext
          • 它是从类的根路径下加载配置文件【推荐使用】
        • FileSystemXmlApplicationContext:
          • 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
        • AnnotationConfigApplicationContext:
          • 当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
    • 3.2 IOC 中 bean 标签和管理对象细节

      • 3.2.1 bean 标签

        • 作用:
          • 用于配置对象让 spring 来创建的。
          • 默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
        • 属性:
          • id:给对象在容器中提供一个唯一标识。用于获取对象。
          • class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
          • scope:指定对象的作用范围。
            • singleton :默认值,单例的.
            • prototype :多例的.
            • request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
            • session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
            • global session :WEB 项目中,应用在 Portlet 环境。如果没有 Portlet 环境那么 globalSession 相当于 session.
          • init-method:指定类中的初始化方法名称。
          • destroy-method:指定类中销毁方法名称。
      • 3.2.2 bean 的作用范围和生命周期

        • 单例对象:scope="singleton"
          • 一个应用只有一个对象的实例。它的作用范围就是整个引用。
          • 生命周期:
            • 对象出生:当应用加载,创建容器时,对象就被创建了。
            • 对象活着:只要容器在,对象一直活着。
            • 对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
        • 多例对象:scope="prototype"
          • 每次访问对象时,都会重新创建对象实例。
          • 生命周期:
            • 对象出生:当使用对象时,创建新的对象实例。
            • 对象活着:只要对象在使用中,就一直活着。
            • 对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。
      • 3.2.3 实例化 Bean 的三种方式 

        • 第一种方式:使用默认无参构造函数
          • 在默认情况下:它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。
          • <bean id="accountService" 
                class="com.itheima.service.impl.AccountServiceImpl"/>
        • 第二种方式:spring 管理静态工厂-使用静态工厂的方法创建对象
          • /**
            * 模拟一个静态工厂,创建业务层实现类
            */
            public class StaticFactory {
                public static IAccountService createAccountService(){
                    return new AccountServiceImpl();
                }
            }
          • 此种方式是:
            • 使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器
            • id 属性:指定 bean 的 id,用于从容器中获取
            • class 属性:指定静态工厂的全限定类名
            • factory-method 属性:指定生产对象的静态方法
          • <bean id="accountService"
             class="com.itheima.factory.StaticFactory"
             factory-method="createAccountService"></bean>
        • 第三种方式:spring 管理实例工厂-使用实例工厂的方法创建对象
          • /**
            * 模拟一个实例工厂,创建业务层实现类
            * 此工厂创建对象,必须现有工厂实例对象,再调用方法
            */
            public class InstanceFactory {
                public IAccountService createAccountService(){
                    return new AccountServiceImpl();
                }
            }
          •  此种方式是:
            • 先把工厂的创建交给 spring 来管理。
            • 然后在使用工厂的 bean 来调用里面的方法
            • factory-bean 属性:用于指定实例工厂 bean 的 id。
            • factory-method 属性:用于指定实例工厂中创建对象的方法。
            • <bean id="instancFactory" 
                  class="com.itheima.factory.InstanceFactory">
              </bean>
              
              <bean id="accountService"
               factory-bean="instancFactory"
               factory-method="createAccountService">
              </bean>

    • 3.3 spring 的依赖注入

      • 3.3.1 依赖注入的概念

        • 依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。
        • 程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。
        • ioc 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
        • 那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。
        • 简单的说,就是坐等框架把持久层对象传入业务层,而不用自己去获取。
      • 3.3.2 构造函数注入

        • 顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作通过配置的方式,让 spring 框架来注入。具体代码如下:
        • public class AccountServiceImpl implements IAccountService {
              
              private String name;
              private Integer age;
              private Date birthday;
              
              public AccountServiceImpl(String name, Integer age, Date birthday) {
                  this.name = name;
                  this.age = age;
                  this.birthday = birthday;
              }
          
              @Override
              public void saveAccount() {
                  System.out.println(name+","+age+","+birthday);
              }
          }
        • 使用构造函数的方式,给 service 中的属性传值
        • 要求:
          • 类中需要提供一个对应参数列表的构造函数。
        • 涉及的标签:
          • constructor-arg
          • 属性:
            • 找给谁赋值
              • index:指定参数在构造函数参数列表的索引位置
              • type:指定参数在构造函数中的数据类型
              • name:指定参数在构造函数中的名称 用这个找给谁赋值
            • 赋什么值
              • value:它能赋的值是基本数据类型和 String 类型
              • ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
              • <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
                    <constructor-arg name="name" value="张三"></constructor-arg>
                    <constructor-arg name="age" value="18"></constructor-arg>
                    <constructor-arg name="birthday" ref="now"></constructor-arg>
                </bean>
                
                <bean id="now" class="java.util.Date"></bean>
      • 3.3.3 set 方法注入

        • 顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:
        • public class AccountServiceImpl implements IAccountService {
              
              private String name;
              private Integer age;
              private Date birthday;
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public void setAge(Integer age) {
                  this.age = age;
              }
          
              public void setBirthday(Date birthday) {
                  this.birthday = birthday;
              }
          
              @Override
              public void saveAccount() {
                  System.out.println(name+","+age+","+birthday);
              }
          }
        • 通过配置文件给 bean 中的属性传值:使用 set 方法的方式涉及的标签:
          • property-属性:
            • name:找的是类中 set 方法后面的部分
            • ref:给属性赋值是其他 bean 类型的
            • value:给属性赋值是基本数据类型和 string 类型的
              • 实际开发中,此种方式用的较多。
          • <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
                <property name="name" value="test"></property>
                <property name="age" value="21"></property>
                <property name="birthday" ref="now"></property>
            </bean>
            <bean id="now" class="java.util.Date"></bean>
      • 3.3.4 使用 p 名称空间注入数据(本质还是调用 set 方法)

        • 此种方式是通过在 xml 中导入 p 名称空间,使用 p:propertyName 来注入数据,它的本质仍然是调用类中的set 方法实现注入功能。
        • public class AccountServiceImpl4 implements IAccountService {
              
              private String name;
              private Integer age;
              private Date birthday;
          
              public void setName(String name) {
                  this.name = name;
              }
          
              public void setAge(Integer age) {
                  this.age = age;
              }
          
              public void setBirthday(Date birthday) {
                  this.birthday = birthday;
              }
          
              @Override
              public void saveAccount() {
                  System.out.println(name+","+age+","+birthday);
              }
          }
        • 配置文件代码:
        • <beans xmlns="http://www.springframework.org/schema/beans"
              xmlns:p="http://www.springframework.org/schema/p"
              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="accountService" 
                  class="com.itheima.service.impl.AccountServiceImpl4"
                  p:name="test" p:age="21" p:birthday-ref="now"/>
          </beans>
      • 3.3.5 注入集合属性

        • 顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。
        • 这里介绍注入数组,List,Set,Map,Properties。具体代码如下:
        • public class AccountServiceImpl implements IAccountService {
          
              private String[] myStrs;
              private List<String> myList;
              private Set<String> mySet;
              private Map<String,String> myMap;
              private Properties myProps;
          
              public void setMyStrs(String[] myStrs) {
                  this.myStrs = myStrs;
              }
          
              public void setMyList(List<String> myList) {
                  this.myList = myList;
              }
          
              public void setMySet(Set<String> mySet) {
                  this.mySet = mySet;
              }
          
              public void setMyMap(Map<String, String> myMap) {
                  this.myMap = myMap;
              }
          
              public void setMyProps(Properties myProps) {
                  this.myProps = myProps;
              }
          
              @Override
              public void saveAccount() {
                  System.out.println(Arrays.toString(myStrs));
                  System.out.println(myList);
                  System.out.println(mySet);
                  System.out.println(myMap);
                  System.out.println(myProps);
              }
          }

          ​​​​​​​​​​​​​​

        • 注入集合数据
          • List 结构:array, list, set
          • Map 结构: map, entry, props, prop
        • <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
          
              <!-- 在注入集合数据时,只要结构相同,标签可以互换 -->
              <!-- 给数组注入数据 -->
              <property name="myStrs">
                  <set>
                      <value>AAA</value>
                      <value>BBB</value>
                      <value>CCC</value>
                  </set>
              </property>
          
              <!-- 注入 list 集合数据 -->
              <property name="myList">
                  <array>
                      <value>AAA</value>
                      <value>BBB</value>
                      <value>CCC</value>
                  </array>
              </property>
          
              <!-- 注入 set 集合数据 -->
              <property name="mySet">
                  <list>
                      <value>AAA</value>
                      <value>BBB</value>
                      <value>CCC</value>
                  </list>
              </property>
          
              <!-- 注入 Map 数据 -->
              <property name="myMap">
                  <props>
                      <prop key="testA">aaa</prop>
                      <prop key="testB">bbb</prop>
                  </props>
              </property>
          
              <!-- 注入 properties 数据 -->
              <property name="myProps">
                  <map>
                      <entry key="testA" value="aaa"></entry>
                      <entry key="testB">
                          <value>bbb</value>
                      </entry>
                  </map>
              </property>
          </bean>
          ​​​​​​​
  • 4 Spring 配置文件中提示的配置

    • ​​​​​​​​​​​​​​
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值