SpringIOC机制详解

6 篇文章 2 订阅

一、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多例的
requestWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
sessionWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
global sessionWEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session

2、bean作用域的解析

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

Bean的实例化个数:1个

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

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

Bean的实例化个数:多个

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

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

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

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

互联网底层民工

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

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

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

打赏作者

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

抵扣说明:

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

余额充值