spring(一)spring概述、spring体系结构、IOC详解、手写简单IOC容器、bean的自动装配

本文详细介绍了Spring框架,从Spring的核心模块、体系结构到IOC(控制反转)概念,包括BeanFactory和ApplicationContext容器。通过示例展示了如何通过配置文件管理Bean,如依赖注入、Bean的自动装配等,最后探讨了IOC容器的功能和实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Spring概述

官网相关

spring概述

  ①Spring是一个开源框架
  ②Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。
③Spring是一个IOC(DI)和AOP容器框架。
④Spring的优良特性
  [1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
  [2]控制反转:IOC——Inversion of Control,指的是将对象的创建权交给Spring去创建。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。
  [3]依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用setXX方法去设置,而是通过配置赋值。
  [4]面向切面编程:Aspect Oriented Programming——AOP
  [5]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
   [6]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
   [7]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。

2、Spring体系结构

Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。下面的部分对在 Spring 框架中所有可用的模块给出了详细的介绍。

Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用。
在这里插入图片描述

核心容器

  1. 核心容器由核心,Bean,上下文和表达式语言模块组成,它们的细节如下: 核心模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

2 Bean 模块提供 BeanFactory,它是一个工厂模式的复杂实现。

3 上下文模块建立在由核心和 Bean 模块提供的坚实基础上,它是访问定义和配置的任何对象的媒介。ApplicationContext
接口是上下文模块的重点。

4 表达式语言模块在运行时提供了查询和操作一个对象图的强大的表达式语言。

数据访问/集成

  1. 数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

  2. JDBC 模块提供了删除冗余的 JDBC 相关编码的 JDBC 抽象层。

  3. ORM 模块为流行的对象关系映射 API,包括 JPA,JDO,Hibernate 和 iBatis,提供了集成层。

  4. OXM 模块提供了抽象层,它支持对 JAXB,Castor,XMLBeans,JiBX 和 XStream 的对象/XML 映射实现。

  5. Java 消息服务 JMS 模块包含生产和消费的信息的功能。

  6. 事务模块为实现特殊接口的类及所有的 POJO 支持编程式和声明式事务管理。

Web
Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

  1. Web 模块提供了基本的面向 web 的集成功能,例如多个文件上传的功能和使用 servlet 监听器和面向 web
    应用程序的上下文来初始化 IoC 容器。
  2. Web-MVC 模块包含 Spring 的模型-视图-控制器(MVC),实现了 web 应用程序。
  3. Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web
    应用程序中提供了客户端和服务器端之间通信的两种方式。
  4. Web-Portlet 模块提供了在 portlet 环境中实现 MVC,并且反映了 Web-Servlet 模块的功能。

其他

还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

  1. AOP 模块提供了面向方面的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,它实现了应该分离的功能。
  2. Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
  3. Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
  4. Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket
    子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
  5. 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

Spring框架分为四大模块:

  Core核心模块。负责管理组件的Bean对象
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar

  面向切面编程
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar

  数据库操作
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-oxm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
spring-jms-4.0.0.RELEASE.jar

  Web模块
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar
spring-websocket-4.0.0.RELEASE.jar
spring-webmvc-portlet-4.0.0.RELEASE.jar

依赖注入(DI)

  Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。

  当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用额可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。

  到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。

  依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。

面向方面的程序设计(AOP):

Spring 框架的一个关键组件是面向方面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。

在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。

Spring 框架的 AOP 模块提供了面向方面的程序设计实现,允许你定义拦截器方法和切入点,可以实现将应该被分开的代码干净的分开功能。我将在一个独立的章节中讨论更多关于 Spring AOP 的概念。

环境搭建

1 、下载 Spring5
在这里插入图片描述

(1)使用 Spring 最新稳定版本 5.2.6
(2)下载地址
https://repo.spring.io/release/org/springframework/spring/
在这里插入图片描述在这里插入图片描述

2 、打开 idea 工具,创建普通 Java 工程
在这里插入图片描述

3 、导入 Spring5 相关 jar 包
在这里插入图片描述在这里插入图片描述首先创建实体类

public class User {
   
    private Integer id;
    private String name;
    private Integer age;
    private String phone;
    //省略getset方法,构造器,tostring方法
    }

写配置文件一般叫做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-3.0.xsd">
    <bean id="person" class="com.zy.entity.User">
        <property name="id" value=" 21"/>
        <property name="name" value=" 小脑斧"/>
        <property name="age" value=" 21"/>
        <property name="phone" value=" 2291689267"/>
    </bean>
</beans>

最后测试

 @Test
    public void test(){
   
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        User user = context.getBean(User.class);
        System.out.println(user);
    }

在这里插入图片描述

3.IOC

1、什么是IOC(控制反转)

​ a)把对象创建和对象之间的调用过程,交给Spring进行管理

​ b)使用IOC目的:为了降低耦合度

​ 2、IOC底层

​ a)xml解析、工厂模式、反射
3、两种实现: 依赖查找(DL)和依赖注入(DI)。

ioc容器

​ Spring提供的IOC容器实现的两种方式(两个接口)
  BeanFactory 粗暴简单,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。

  ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。

例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。

该接口定义了一个 refresh 方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 bean。

当然,除了这两个大接口,还有其他的辅助接口

BeanFactory容器

  是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactor 中被定义。 BeanFactory 和相关的接口,比如,BeanFactoryAware、 DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。

  在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。

  在资源宝贵的移动设备或者基于 applet 的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext,除非你有更好的理由选择 BeanFactory。

@Test
    public void test1(){
   
        XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("ApplicationContext.xml"));
        User user = factory.getBean(User.class);
        System.out.println(user);
    }

注意:
XmlBeanFactoty(new ClassPathResource)这种获取工厂对象再获取bean的方式有点过时,不建议使用

  1. 第一步利用框架提供的 XmlBeanFactory() API 去生成工厂 bean 以及利用 ClassPathResource()
    API 去加载在路径 CLASSPATH 下可用的 bean 配置文件。XmlBeanFactory() API
    负责创建并初始化所有的对象,即在配置文件中提到的 bean。
  2. 第二步利用第一步生成的 bean 工厂对象的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID
    来返回一个真正的对象,该对象最后可以用于实际的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。

在这里插入图片描述

ApplicationContext 容器

  Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件从解析文本信息和将事件传递给所指定的监听器。这个容器在 org.springframework.context.ApplicationContext interface 接口中定义。

  ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会被推荐使用。BeanFactory 仍然可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。

最常被使用的 ApplicationContext 接口实现:

  1. FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的
    bean。在这里,你需要提供给构造器 XML 文件的完整路径
  2. ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供
    XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
  3. WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
@Test
    public void test2(){
   
        ApplicationContext context = new FileSystemXmlApplicationContext("E:\\daima1\\frame\\spring\\spring-01\\src\\main\\resources\\ApplicationContext.xml");
        User person = (User) context.getBean("person");
        System.out.println(person);
    }

注意

  1.   第一步生成工厂对象。加载完指定路径下 bean 配置文件后,利用框架提供的
    FileSystemXmlApplicationContext API 去生成工厂
    bean。FileSystemXmlApplicationContext 负责生成和初始化所有的对象,比如,所有在 XML bean
    配置文件中的 bean。
  2.   第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的
    bean ID 来返回一个真正的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。

ClassPathXmlApplicationContext 类

  为了更直观的展示 “低级容器” 和 “高级容器” 的关系,我这里通过常用的 ClassPathXmlApplicationContext 类,来展示整个容器的层级 UML 关系。

在这里插入图片描述

下面的 3 个绿色的,都是功能扩展接口,这里就不展开讲。

  看下面的隶属 ApplicationContext 粉红色的 “高级容器”,依赖着 “低级容器”,这里说的是依赖,不是继承哦。他依赖着 “低级容器” 的 getBean 功能。而高级容器有更多的功能:支持不同的信息源头,可以访问文件资源,支持应用事件(Observer 模式)。

  通常用户看到的就是 “高级容器”。 但 BeanFactory 也非常够用啦!

  左边灰色区域的是 “低级容器”, 只负载加载 Bean,获取 Bean。容器其他的高级功能是没有的。例如上图画的 refresh 刷新 Bean 工厂所有配置。生命周期事件回调等。

  好,解释了低级容器和高级容器,我们可以看看一个 IoC 启动过程是什么样子的。说白了,就是 ClassPathXmlApplicationContext 这个类,在启动时,都做了啥。

ClassPathXmlApplicationContext 的构造过程

下图是 ClassPathXmlApplicationContext 的构造过程,实际就是 Spring IoC 的初始化过程。

在这里插入图片描述

注意,这里为了理解方便,有所简化。

这里再用文字来描述这个过程:

①、用户构造 ClassPathXmlApplicationContext(简称 CPAC)

②、CPAC 首先访问了 “抽象高级容器” 的 final 的 refresh 方法,这个方法是模板方法。所以要回调子类(低级容器)的 refreshBeanFactory 方法,这个方法的作用是使用低级容器加载所有 BeanDefinition 和 Properties 到容器中。

③、低级容器加载成功后,高级容器开始处理一些回调,例如 Bean 后置处理器。回调 setBeanFactory 方法。或者注册监听器等,发布事件,实例化单例 Bean 等等功能,这些功能,随着 Spring 的不断升级,功能越来越多,很多人在这里迷失了方向 :)。

简单说就是:

④、低级容器 加载配置文件(从 XML,数据库,Applet),并解析成 BeanDefinition 到低级容器中。

⑤、加载成功后,高级容器启动高级功能,例如接口回调,监听器,自动实例化单例,发布事件等等功能。

所以,一定要把 “低级容器” 和“高级容器” 的区别弄清楚。不能一叶障目不见泰山。

getBean 的流程

当我们创建好容器,就会使用 getBean 方法,获取 Bean,而 getBean 的流程如下:
在这里插入图片描述

从图中可以看出,getBean 的操作都是在低级容器里操作的。其中有个递归操作,这个是什么意思呢?

假设:当 Bean_A 依赖着 Bean_B,而这个 Bean_A 在加载的时候,其配置的 ref = “Bean_B” 在解析的时候只是一个占位符,被放入了 Bean_A 的属性集合中,当调用 getBean 时,需要真正 Bean_B 注入到 Bean_A 内部时,就需要从容器中获取这个 Bean_B,因此产生了递归。

为什么不是在加载的时候,就直接注入呢?因为加载的顺序不同,很可能 Bean_A 依赖的 Bean_B 还没有加载好,也就无法从容器中获取,你不能要求用户把 Bean 的加载顺序排列好,这是不人道的。

所以,Spring 将其分为了 2 个步骤:

     ①、加载所有的 Bean 配置成 BeanDefinition 到容器中,如果 Bean 有依赖关系,则使用占位符暂时代替。

     ②、然后,在调用 getBean 的时候,进行真正的依赖注入,即如果碰到了属性是 ref 的(占位符),那么就从容器里获取这个 Bean,然后注入到实例中 —— 称之为依赖注入。

可以看到,依赖注入实际上,只需要 “低级容器” 就可以实现。

这就是 IoC。

所以 ApplicationContext refresh 方法里面的操作不只是 IoC,是高级容器的所有功能(包括 IoC),IoC 的功能在低级容器里就可以实现。

手写一个简单的ioc

package com.zy.ioc;


import org.w3c.dom.Document
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值