一、IOC概述及作用

(一)IOC的简介,设计思想

SpringIOC:IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。

IOC这个概念简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部透明的,从而降低了解决问题的复杂度,而且可以灵活的被重用和扩展。

IOC理论提出的观点大体是这样的:借助于第三方实现具有依赖关系的对象之间的解耦。

img编辑

由于引进了中间位置“第三方”,也就是IOC容器,使得A、B、C、D这四个对象没有了耦合关系,齿轮之间的传动全部依靠IOC容器,全部对象的控制权上交给IOC容器,所以IOC容器成了整个系统的关键核心,它起到一个“粘合剂”的作用,把系统中所有对象粘合在一起发挥作用。

img编辑

当把图中的IOC容器拿掉,可以发现A、B、C、D这四个 对象之间没有耦合关系。这样的话,当我们去实现A的时候,根本无需去考虑其他几个对象,对象之间的依赖关系已经讲到了最低程度。

(二)IOC作用

IOc本质上就是一个大工程,大容器。主要作用就是创建和管理对象的依赖关系,削减计算机程序的耦合(解除我们代码间的依赖关系),提高程序的可扩展性和可维护性。

二、SpringIOC入门案例前期准备

(一)构建maven工程,添加Spring框架的依赖

<properties>
    <spring.version>5.2.5.RELEASE</spring.version>
</properties>
<!--导入spring的context坐标,context依赖core、beans、expression aop-->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

(二)创建持久层接口和实现类

public interface UserDao {
    public void save();
}
​
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("userDao save method running...... ");
    }
}

(三)创建业务层接口和实现类

public interface UserService {
    public void saveService();
}
​
public class UserServiceImpl implements UserService {
    @Override
    public void saveService() {
        System.out.println("userSerivce save method running......");
    }
}

(四)在resources文件夹中创建一个任意名称的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/springbeans.xsd">
</beans>

(五)让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">
​
    <!--配置userDaoImpl-->
    <bean id="userDao" class="com.ujiuye.dao.impl.UserDaoImpl"></bean>
    <!--配置userServiceImpl-->
    <bean id="userService" class="com.ujiuye.service.UserServiceImpl"></bean>
</beans>

(六)测试IOC配置是否成功

@Test
public void test1(){
    //1:获得spring IOC容器对象:
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
    //2:从容器当中根据id获得UserDaoImpl 对象,执行userDao对象的save方法
    UserDao userDao = (UserDao) applicationContext.getBean("userDao");
    userDao.save();
​
    //3:从容器当中根据id获得UserServiceImpl 对象,执行userService对象的saveService
方法
    UserService userService = (UserService)applicationContext.getBean("userService");
    userService.saveService();
}

运行结果:

img编辑

三、Spring基于XML的IOC细节

(一)IOC配置文件详解:配置标签书写规范,配置标签的属性

bean标签:用于配置对象交给Spring来创建

默认情况下他会调用类中无参数的构造器,如果没有无参数构造器则不能创建成功。

基本属性:

id:Bean实例对象在Spring容器中的唯一标识

class:Bean的全限定类名

(二)SpringIOC机制源码解析

1、IOC容器解析

IOC思想基于IOC容器完成,IOC容器底层就是对象工厂,Spring中工厂的类结构图如下;

img编辑

(1)BeanFactory

IOC容器的基本实现,是Spring内部使用的接口,不提供开发人员使用,加载配置文件时,不会创建对象,在获得(使用)对象时才采取创建对象。

(2)HierarchicalBeanFactory

这个工厂接口非常简单,实现了Bean工厂的分层。工厂接口也是继承自BeanFactory,也是一个二级接口,相对于父接口,他只是扩展了一个重要的功能———工厂分层

(3)AutowireCapableBeanFactory

该接口有自动配置能力,需要注意的是,ApplicationContext接口并实现此接口,因为应用代码很少用到此功能,如果确实需要的话,可以调用ApplicationContext getAutowireCapableBeanFactory方法,来获取此接口的实例。

(4)ListableBeanFactory

获取bean时,Spring鼓励使用这个接口定义的api,如查看bean的个数、获取某一类型Bean的配置名、查看容器中是否包括某一Bean等方法。

(5)ApplicationContext

BeanFactory接口的子接口,提供更多强大的功能,一般由开发人员使用。接口提供了bean基础性操作同时,扩展了国际化等功能。ApplicationContext接口在加载配置文件时候就会配置文件当中的对象进行创建,存放IOC容器当中

(6)AnnotationConfigApplicationContext

当使用注解配置容器对象时,需要使用此类来创建spring容器。他用来读取注解。

(7)ClassPathXmlApplicationContext

它是从类的根路径下加载配置文件

(8)FileSystemXmlApplicationContext

它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

2、IOC容器底层bean初始化过程

img编辑

(1)BeanFactionPostProcessor

作用:定义了在bean工厂对象创建后,bean对象创建前执行的动作,用于对工厂进行创建后业务处理

运行时机:操作用于对工厂进行处理,仅运行一次

(2) BeanPostProcessor

作用:定义了所有bean初始化前后进行的统一动作,用于对bean进行创建前业务处理与创建后业务处理

运行时机:当前操作伴随着每个bean的创建过程,每次创建bean均运行该操作。

(3)InitializingBean

作用:定义了每个bean的初始化前进行的动作,属于非统一性动作,用于对bean进行创建前业务处理。

运行时机:当前操作伴随着任意一个bean的创建过程,保障其个性化业务处理

四、手动实现自己的IOC容器

(一)分析IOC实现思路

img编辑

(二)IOC原理实现—环境搭建:构建maven工程,引入依赖

<properties>
        <spring.version>5.2.5.RELEASE</spring.version>
    </properties>
​
    <dependencies>
        <!--导入spring的context坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--导入junit单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

(三)设计接口和类以及编写配置文件

//设定UserDao接口
public interface UserDao {
    public void save();
}
//设定UserDao接口实现类
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("userDao save method running...... ");
    }
}

配置文件:

<!--配置userDaoImpl-->
<bean id="userDao" class="com.ujiuye.dao.impl.UserDaoImpl"></bean>

(四)使用xml技术解析配置文件

<!--引入dom4J-->
<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
</dependency>

/**
* 创建自己的工厂类
*/
public class MyBeanFactory {
​
    //创建一个map集合,模拟IOC容器
    private static Map<String,Object> map = new HashMap<>();
​
    static{
        try {
            //使用dom4J 解析xml文件:
            //第一步:获得一个解析器:
            SAXReader reader = new SAXReader();
            //第二: 读取外部的配置文件:
            String path = "src/main/resources/applicationContext.xml";
            //第三: 读取了整个文档对象
            Document document = reader.read(path);
            //第四: 获得根节点:
            Element rootElement = document.getRootElement();//beans
            //第五: 获得根节点下的所有的bean 标签对应的节点:
            List<Element> bean = rootElement.elements("bean");// bean
            for (Element element : bean) {
                //获得id属性对应的值:
                String id1 = element.attributeValue("id");
                //获得class属性对应的值:【全限定类名】
                String aClass = element.attributeValue("class");//获得class对应的值: 全限定类名。
                //通过反射创建对象:
                Class clz = Class.forName(aClass);
                Object object = clz.newInstance();
                //存容器 id做key,创建出来的对象value
                map.put(id1,object);
            }
​
        } catch (Exception e) {
            e.printStackTrace();
    }
}

/**
* 根据id从容器当中获得对象
* @param id id的名称
* @return 返回Object类型对象
*/
public static Object getBean(String id){
    Object o = map.get(id);
    return o;
    }
}

(五)编写测试文件,展示测试结果

@Test
public void testMyFactory(){
    //1:创建工厂对象
    MyBeanFactory factory =new MyBeanFactory();
    //2:从容器当中根据id获得对象
    UserDao userDao = (UserDao) factory.getBean("userDao");
    System.out.println(userDao);
    userDao.save();
}

五、Spring管理bean细节

(一)bean实例化方式

1、构造方法的方式

(1)创建User类
public class User implements Serializable {
    public User(){
        System.out.println("user created...");
    }
}

(2)配置Spring容器管理user类型对象
<!--配置user对象-->
<bean id="user" class="com.ujiuye.pojo.User"></bean>

(3)测试容器实例化User对象是否成功)
@Test
public void testUser(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    User user = (User) context.getBean("user");
    System.out.println(user);
}

2、静态工厂方式

(1)创建静态工厂ItemFactory
public class ItemFactory {
    //静态方法返回实例bean
    public static User createUser(){
        System.out.println("static method running create bean ......");
        return new User();
    }
}

(2)配置Spring容器管理User类型对象
<!--静态工厂实例化对象-->
<bean id="user" class="com.ujiuye.factory.ItemFactory"></bean>

(3)测试容器实例化User对象是否成功
@Test
public void testItemFactory(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    User user = (User) context.getBean("user");
    System.out.println(user);
}

3、实例工厂方式

(1)创建实例工厂NewItemFactory
public class NewItemFactory {
    //工厂的非静态方法返回bean实例
    public User createUser(){
        System.out.println("Dynamic method running create bean ......");
        return new User();
    }
}

(2)配置Spring容器管理NewItemFactory类型对象
<!--实例工厂-->
<bean id="itemFactory" class="com.ujiuye.factory.NewItemFactory"></bean>
<bean id="user" factory-bean="itemFactory" factory-method="createUser"></bean>
(3)测试容器实例化User对象是否成功
@Test
public void testNewItemFactory(){
    ApplicationContext context =
    new ClassPathXmlApplicationContext("applicationContext.xml");
    User user = (User) context.getBean("user");
    System.out.println(user);
}

(二)bean作用域

1、bean作用域介绍

所谓Bean的作用域其实就是指Spring给我们创建出的对象的存活范围,在配置文件中通过bean的scope属性指定

scope:指对象的作用范围,取值如下:

取值范围 说明
singleton 默认值,单例的
prototype 多例的
request WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
session WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
global session WEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session

2、bean作用域的解析

(1)当**scope的取值为singleton时**

Bean的实例化个数:1个

Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例

(2)当**scope的取值为prototype时**

Bean的实例化个数:多个

Bean的实例化时机:当调用getBean()方法时实例化Bean

(3)当**Scope的取值为其他值**

scope指定为其他值,需要在特定的环境下使用。

推荐内容
阅读全文
AI总结
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐