Spring的IOC和DI

扫码查看

1 控制反转

1.1 什么是工厂?

  • 工厂就是负责给我们从容器中获取制定对象的累。这时候我们获取对象的方式发生了改变。
  • 原来:我们在获取对象的时候,都是采用new的方式,是主动的。
  •  现在:我们获取对象的时候,是和工厂要的,由工厂为我们查找或创建对象。是被动的。
  •  这种被动接收的方式获取对象的思想就是控制反转,它是Spring框架的核心之一。

1.2 概念

  • 控制反转把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语。
  • 它包括依赖注入和依赖查找。

1.3 明确IOC的作用

  • 削减计算机程序的耦合(解除我们代码中的依赖关系)。

2 使用Spring的IOC解决程序的耦合

2.1案例的前期准备

  • 本次的案例是账户的业务层和持久层的依赖关系的解决。在开始Spring的配置之前,我们要先准备一下环境。由于我们是使用Spring解决依赖关系,并不是真正的增删改查操作,所以我们没必要写实体类。并且我们在此处使用的是Java工程,不是Javaweb工程。

2.1.1 导入Spring的maven坐标

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
  • 注意:Spring5是使用JDK8编写的,所以要求我们的JDK版本是8及以上。同时Tomcat的脚本要求是5.5及以上。

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

  • IAccountDao.java
package com.sunxiaping.spring5.dao;

/**
 * 账户的持久层接口
 */
public interface IAccountDao {
    /**
     * 保存账户
     */
    void saveAccount();
}
  • AccountDaoImpl.java
package com.sunxiaping.spring5.dao.impl;

import com.sunxiaping.spring5.dao.IAccountDao;

/**
 * 账户的持久层实现类
 */
public class AccountDaoImpl implements IAccountDao {
    @Override
    public void saveAccount() {
        System.out.println("保存账户了");
    }
}

2.1.3 创建业务层和实现类

  • IAccountService.java
package com.sunxiaping.spring5.service;

/**
 * 账户的业务层接口
 */
public interface IAccountService {
    /**
     * 保存账户
     */
    void saveAccount();
}
  • AccountServiceImpl.java
package com.sunxiaping.spring5.service.impl;

import com.sunxiaping.spring5.dao.IAccountDao;
import com.sunxiaping.spring5.dao.impl.AccountDaoImpl;
import com.sunxiaping.spring5.service.IAccountService;

public class AccountServiceImpl implements IAccountService {
    //此处的依赖关系有待解决
    private IAccountDao accountDao = new AccountDaoImpl();

    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

2.2 基于XML的配置

2.2.1 在resources目录下新建applicationContext.xml文件

  • applicationContext.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">


</beans>

2.2.2 让Spring管理资源,在配置文件中配置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">

    <!--
        bean标签:用于配置让Spring创建对象,并且存入IOC容器之中
            id属性:对象的唯一标识
            class属性:指定要创建对象的全限定类名
    -->
    <!-- 配置dao -->
    <bean id="accountDao" class="com.sunxiaping.spring5.dao.impl.AccountDaoImpl"></bean>

    <!-- 配置service -->
    <bean id="accountService" class="com.sunxiaping.spring5.service.impl.AccountServiceImpl"></bean>
</beans>

2.2.3 测试是否配置成功

  • 示例:测试
package com.sunxiaping;

import com.sunxiaping.spring5.dao.IAccountDao;
import com.sunxiaping.spring5.service.IAccountService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class spring5Test {

    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        IAccountDao accountDao = context.getBean("accountDao", IAccountDao.class);
        System.out.println("accountDao:" + accountDao);
        IAccountService accountService = context.getBean("accountService", IAccountService.class);
        System.out.println("accountService:" + accountService);
    }

}

2.3 Spring基于XML的IOC细节

2.3.1 Spring中的工厂的类结构图

2.3.1.1 BeanFactory和ApplicationContext的区别

  • BeanFactory是Spring容器中的顶层接口。
  • ApplicationContext是BeanFactory的子接口。
  • BeanFactory和ApplicationContext的区别:
  • ①创建对象的时间点不一样:
    • BeanFactory:什么时候使用什么时候创建对象。采用的是延迟加载的方式。多例对象适用。
    • ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。采用的是立即加载的方式。单例对象适用。  

2.3.1.2 ApplicationContext接口的实现类

  • ClassPathXMLApplicationContext:它是从类的classpath路径下加载配置文件。推荐使用这种。
  • FileSystemXMLApplicationContext:它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任何位置。
  • AnnotationConfigApplicationContext:当我们使用注解配置容器对象的时候,需要使用此类来创建Spring容器。它是用来读取注解的。

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

2.3.2.1 bean标签

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

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

  • 单例对象:scope="singleton"
  • 一个应用只有一个对象的实例。
  • 生命周期:
    • 对象出生:当应用加载,创建容器的时候,对象就被创建了。
    • 对象活着:只要容器在,对象一直活着。
    • 对象死亡:当应用卸载的时候,销毁容器的时候,对象就被销毁了。  
  • 多例对象:scope=“prototype”
  • 每次访问对象的时候,都会重新创建对象实例。
  • 生命周期:
    • 对象出生:当使用对象的时候,创建新的对象实例。
    • 对象活着:只要对象在使用中,就一直活着。
    • 对象死亡:当对象长时间不用的时候,被Java的垃圾回收器回收了。  

2.3.2.3 实例化Bean的三种方式

  • 第一种方式:使用默认的无参构造方法
  • IAccountService.java  
package com.sunxiaping.spring5.service;

/**
 * 账户的业务层接口
 */
public interface IAccountService {
    /**
     * 保存账户
     */
    void saveAccount();
}
View Code
  • AccountServiceImpl.java
package com.sunxiaping.spring5.service.impl;

import com.sunxiaping.spring5.service.IAccountService;

public class AccountServiceImpl implements IAccountService {

    @Override
    public void saveAccount() {
        System.out.println("保存账户信息");
    }
}
View Code
  • applicationContext.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">

    <!-- 在默认情况下,Spring会根据默认无参构造方法来创建类对象。如果Bean中没有默认无参构造方法,将会创建失败 -->
    <bean id="accountService" class="com.sunxiaping.spring5.service.impl.AccountServiceImpl"></bean>
</beans>
  • 第二种方式:Spring管理实例工厂,使用实例工厂的方法创建对象
  • InstanceFactory.java
package com.sunxiaping.spring5.factory;

import com.sunxiaping.spring5.service.IAccountService;
import com.sunxiaping.spring5.service.impl.AccountServiceImpl;

/**
 * 模拟一个实例工厂,创建业务层实现类
 * 此工厂创建对象,必须先有工厂实例对象,再调用方法
 */
public class InstanceFactory {

    public IAccountService getInstance() {
        return new AccountServiceImpl();
    }
}
  • applicationContext.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">

    <!--
        此种方式是:
        先把工厂的创建交给Spring管理。然后再使用工厂的Bean来调用里面的方法。
        factory-bean属性:用于指定实例工厂Bean的id。
        factory-method属性:用于指定实例工厂中创建对象的方法。
     -->
    <bean id="instanceFactory" class="com.sunxiaping.spring5.factory.InstanceFactory"></bean>

    <bean id="accountService" factory-bean="instanceFactory" factory-method="getInstance"/>

</beans>
  • 第三种方式:Spring管理静态工厂--使用静态工厂的方法创建对象
  • StaticFactory.java
package com.sunxiaping.spring5.factory;

import com.sunxiaping.spring5.service.IAccountService;
import com.sunxiaping.spring5.service.impl.AccountServiceImpl;

/**
 * 模拟一个静态工厂,创建业务层实现类
 */
public class StaticFactory {

    public static IAccountService getInstance() {
        return new AccountServiceImpl();
    }
}
  • applicationContext.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">

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

</beans>

2.3.3 Spring的依赖注入

01-20 20:37
查看更多