Spring5框架之何为Spring以及IOC容器的底层原理(一篇就会)

本篇主要讲述什么是Spring和它的IOC容器的实现原理,AOP切面编程以后再说。

一、Spring概述

1.1 什么是Spring

Spring是以IOC(控制反转)AOP(面向切面编程)为内核的轻量级开源框架。

狭小方面来说相当于用一个容器来针对管理我们开发中的bean的生命周期。

宽广方面来说它可以集成其它框架技术来完成对JavaEE企业级的开发。

想了解更多可以移步至Spring官网。

1.2 Spring体系结构

在Spring基本体系结构中是这样的:

在这里插入图片描述

从上图可以看出,Spring核心是Core Container来支撑,此外它也可以集成切面,WEB(控制层),以及数据库(持久层)。

核心依赖:

spring-beans 负责配置文件,创建和管理bean,支持依赖注入和控制反转
spring-core 模块的核心基础,包含一些核心的工具类
spring-context 提供上下文的支持,最关键的就是ApplicationContext
spring-expression Spring表达式语言,帮助spring运行时查询和操作对象,获取对象的属性和方法的调用

AOP模块:

spring-aop 对于代理AOP的支持
spring-Aspects 对于Aspect的AOP支持

Web模块:

spring-web 基础的web功能,在Web项目中提供Spring的容器
spring-webmvc 提供基于Servlet的SpringMVC
spring-WebSocket 提供WebSocket功能
spring-webmvc-portlet 提供portlet支持

数据库模块:

spring-jdbc 提供jdbc访问数据库的支持
spring-tx 提供对数据库事务的支持
spring-oxm 提供对象xml的支持
spring-jms 提供对java消息服务的支持

二、IOC与DI

2.1 IOC与DI的关系

对于IOCSpring官网是这样描述的:

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.

译文:

IoC也被称为依赖注入(DI)。它是一个对象仅通过构造函数的参数、工厂方法的参数或在对象实例构造,或从工厂方法返回后在对象实例上设置属性来定义其依赖关系(即,它们使用的其他对象)的过程。然后,容器在创建bean时注入这些依赖项。这个过程基本上是bean本身的逆过程(因此称为控制反转),通过使用类的直接构造或服务定位器模式等机制来控制其依赖项的实例化或位置。

现在通俗易懂的来解释一下:

之前,我们需要硬编码方式去手动的创建对象, 周期。

现在将对象的创建,对象的生命周期以及它们之间的依赖关系全部交给Spring容器去管理,由Spring容器来负责控制对象的生命周期和对象之间的关系。

这种反转就叫做IOC(控制反转),就是通常我们所说的IOC容器

从Spring容器的角度来看,Spring负责被依赖的对象赋值给调用者的成员变量,相当于为调用者注入它依赖的实例,就是Spring的依赖注入(Dependency Inhection)

目的就是降低耦合度

2.2 耦合与解耦

先看我们之前对数据的连接操作:

/**
 * @author jektong
 * @Date 2020/6/18-12:38
 */
public class JdbcTemplate {
    public static void main(String[] args) throws SQLException {
        Connection conn=null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //建立连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bookmanage?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8",
                                               "jektong",
                                               "123456");
            //获取数据库连接的预处理对象
            ps = conn.prepareStatement("select * from book");
            //执行sql,得到结果集
            rs = ps.executeQuery();
            //遍历结果集
           while (rs.next()){
                   System.out.println(rs.getString("bname"));
                   System.out.println(rs.getString("author"));
           }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        }
    }
}

这段代码是最初连接数据库的代码,运行此代码时,必须加入MySQL驱动包,不然会报错,这样就可以理解成程序间的耦合,也就是程序间的存在的依赖关系。

我们可以使用反射来创建JDBC对象,避免用new这个关键字,使用配置文件来获取到创建对象的全限定类名,来达到解耦的目的。

三、IOC过程(原理)

Spring对于IOC的实现主要原理就是XML解析,反射,工厂模式。

下面以图解方式逐渐的来说明什么是IOC原理。

3.1 原始的对象间调用

下图简单的展示了最原始的对象调用的方式,直接在UserService类中的方法去创建UserDao类的对象然后调用UserDao类中的add()方法。

这种原始的方式虽然可以达到我们所需要的效果,但是代码的耦合度太高,如果UserDao中的路径与方法发生变化,毋庸置疑,UserService也要跟着变化。

下面通过工厂模式将上面的过程进行一个解耦:

3.2 工厂模式解耦

现在我们将创建UserDao这个对象使用工厂模式去创建这个对象,然后UserService中用工厂来使用UserDao对象,这样就将这两个对象之间进行了解耦,降低了耦合度。

我们发现UserFactory中也创建了UserDao这个对象,说明对象与对象之间必然会存在着耦合度,但是如何将耦合度降低到最大的程度是值得深究的,很显然上面的这种方式并没有将耦合度降低到最低。

下面再通过加上XML解析与反射就可以将耦合度降到最低。

在这里插入图片描述

3.3 XML,反射实现最大限度解耦

首先,将UserDao对象配置到Spring提供的XML文件中。

<bean id="userDao" class="com.jektong.dao.UserDao"></bean>

再次使用工厂模式去创建UserDao这个对象,不过此时就需要使用XML解析的方式去获取上面xml配置的class标签中的值,也就是类所在的包路径。

得到这个包名之后可以通过反射机制来创建对象,反射创建对象的方法是newInstance(),这个方法要记住。以下是这个过程的伪代码:

class UserFactory{
    public static UserDao getUserDao(){
        String valueName = class.值 // xml解析获取值
        Class classzz = Class.forName(valueName) // 反射或取得类
        return (UserDao)classzz.newInstance();
    }
}

这就是IOC的过程,以上代码是这样实现进一步解耦的,当UserDao这个类发生变化时,比如UserDao路径发生变化,我们只需要修改XML文件中的class标签值即可,无需修改其他额外内容。

在这里插入图片描述

四、IOC容器实现

下面就来说说,Spring是如何使用IOC思想来实现IOC控制反转的。IOC本质是一种思想,那么IOC容器就是它的实现方式。而IOC容器的底层就是对象工厂。

IOC容器的实现方式,Spring提供了两种:BeanFactory与ApplicationContext

1. BeanFactory

IOC最基本的实现,是Spring内部最基本的实现,不提供给开发人员去使用。加载配置文件的时候,使用的是延迟加载的方式,只有获取到某个对象的时候,才会调用getBean()方法的时候才会创建对象,这样做如果出现一些Bean的配置问题就不好被发现。

2. ApplicationContext

作为BeanFactory的子接口,提供更多强大的功能,一般在开发时使用。当加载配置文件的时候,即容器一开始创建的时候,就加载所有的对象,唯一不足就是占用内存比较大。

 ApplicationContext所有的实现类如下:

猜你喜欢

转载自blog.csdn.net/qq_41857955/article/details/126216583
今日推荐