☰
Spring 01:IoC、Bean与依赖注入
2026/10/20 13:43:42 网站建设 项目流程

一、Spring是什么?

  • 轻量级一站式框架
    简化JavaEE开发,涵盖Web、数据访问、事务管理等各层技术,无需依赖重量级服务器(如EJB)。

  • 核心优势

    • 解耦:通过IoC容器管理对象依赖

    • 高效整合:无缝集成MyBatis等主流框架

    • 模块化设计:按需选择Spring模块(Core、AOP、Data等)

  • 和SpringBoot的关系

核心目标

  • Spring:提供 IoC(控制反转)和 AOP(面向切面编程)等基础功能,解决企业级开发的复杂性。
  • SpringBoot:简化 Spring 应用的搭建和配置,减少 XML 和样板代码,实现快速启动和开箱即用。

依赖关系

  • Spring 应用需手动配置大量组件(如数据源、MVC、安全等),而 SpringBoot 通过自动配置简化这一过程。
  • SpringBoot基于 Spring 框架构建,必须依赖 Spring 的核心模块(如spring-context、spring-beans)。

开发体验

  • Spring:需编写大量配置类或 XML 文件,依赖管理繁琐。
  • SpringBoot:通过@SpringBootApplication和Starter 依赖自动装配组件,实现零配置启动。
  • Spring生态定位​​​​
  • Spring Framework是基石

  • Spring Boot简化配置

  • Spring Cloud构建微服务


二、IoC与DI

1. 核心思想

  • IoC:将对象的创建权从程序员反转给Spring容器

  • DI:由容器动态建立对象间的依赖关系(Setter/构造器注入)

<!-- 传统方式:硬编码创建 --> BookDao bookDao = new BookDaoImpl(); <!-- IoC方式:容器创建 --> <bean id="bookDao" class="com.example.BookDaoImpl"/>

2.IOC(Inversion of Control)控制反转

(1)什么是控制反转呢?

使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到

外部,此思想称为控制反转。

  • 业务层要用数据层的类对象,以前是自己new的
  • 现在自己不new了,交给别人[外部]来创建对象
  • 别人[外部]就反转控制了数据层对象的创建权
  • 这种思想就是控制反转

(2)Spring和IOC之间的关系是什么呢?

  • Spring技术对IOC思想进行了实现
  • Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部"
  • IOC思想中的别人[外部]指的就是Spring的IOC容器

(3)IOC容器的作用以及内部存放的是什么?

  • IOC容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象
  • 被创建或被管理的对象在IOC容器中统称为Bean
  • IOC容器中放的就是一个个的Bean对象

(4)当IOC容器中创建好service和dao对象后,程序能正确执行么?

  • 不行,因为service运行需要依赖dao对象
  • IOC容器中虽然有service和dao对象
  • 但是service对象和dao对象没有任何关系
  • 需要把dao对象交给service,也就是说要绑定service和dao对象之间的关系

3.DI(Dependency Injection)依赖注入

(1)什么是依赖注入呢?

在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。

  • 业务层要用数据层的类对象,以前是自己new的
  • 现在自己不new了,靠别人[外部其实指的就是IOC容器]来给注入进来
  • 这种思想就是依赖注入

(2)IOC容器中哪些bean之间要建立依赖关系呢?

  • 这个需要程序员根据业务需求提前建立好关系,如业务层需要依赖数据层,service就要和dao建立依赖关系

4.具体实现

介绍完Spring的IOC和DI的概念后,我们会发现这两个概念的最终目标就是充分解耦,具体实现靠:

  • 使用IOC容器管理bean(IOC)
  • 在IOC容器内将有依赖关系的bean进行关系绑定(DI)
  • 最终结果为:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系.

5. 依赖注入方式

类型配置示例适用场景
Setter注入<property name="dao" ref="bookDao"/>灵活,推荐首选
构造器注入<constructor-arg ref="bookDao"/>强制依赖场景
自动装配<bean autowire="byType"/>简化配置,按类型匹配

关于Setter注入:

  • 对于引用数据类型使用的是<property name="" ref=""/>
  • 对于简单数据类型使用的是<property name="" value=""/>

配置文件的编写配置相对麻烦,因此可以采用自动装配。

IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

自动装配方式有哪些?

  • 按类型(常用)
  • 按名称
  • 按构造方法
  • 不启用自动装配

三、Bean

0.Bean基础配置

<bean id="bean的唯一标识" class="bean的类全名" scope="bean的作用范围,有singleton(默认)和prototype" name="为bean取的别名"/>

整个配置中最常用的就两个属性id和class

1. Bean作用域

<bean scope="singleton"/> <!-- 默认单例,复用对象 --> <bean scope="prototype"/> <!-- 非单例,每次请求新对象 -->
  • 单例优点:减少对象创建开销,提升性能

  • 多例场景:有状态对象(如含成员变量的域对象)

思考

为什么bean默认为单例?

  • bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象
  • bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高

bean在容器中是单例的,会不会产生线程安全问题?

  • 如果对象是有状态对象,即该对象有成员变量可以用来存储数据的,
  • 因为所有请求线程共用一个bean对象,所以会存在线程安全问题。
  • 如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的,
  • 因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。

哪些bean对象适合交给容器进行管理?

  • 表现层对象
  • 业务层对象
  • 数据层对象
  • 工具对象

哪些bean对象不适合交给容器进行管理?

  • 封装实例的域对象,因为会引发线程安全问题,所以不适合。

2. Bean生命周期

初始化顺序

1. 构造方法 → 2. 属性注入 → 3. InitializingBean.afterPropertiesSet() → 4. 自定义init-method

触发销毁

ctx.close(); // 立即关闭容器 ctx.registerShutdownHook(); // JVM关闭前自动回调

销毁顺序

1. DisposableBean.destroy() → 2. 自定义destroy-method

3. Bean实例化三种方式

方式实现
构造方法(默认)<bean class="com.example.BookDaoImpl"/>
静态工厂<bean factory-method="create" class="com.example.Factory"/>
实例工厂(FactoryBean接口)实现FactoryBean<T>,重写getObject()(整合第三方框架常用)
(1)构造方法

测试函数

public interface BookDao { public void save(); } public class BookDaoImpl implements BookDao { public BookDaoImpl() { System.out.println("book dao constructor is running ...."); } public void save() { System.out.println("book dao save ..."); } }

可将public BookDaoImpl()改成private BookDaoImpl(),也能执行成功。

说明内部走的依然是构造函数,能访问到类中的私有构造方法。

显而易见 Spring底层用的是反射。

applicationContext.xml配置Spring容器

<?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 id="bookDao" class="com.mytest.dao.impl.BookDaoImpl"/> </beans>

编写运行程序

public class AppForInstanceBook { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); } }

输出

因为每一个类默认都会提供一个无参构造函 数,所以其实真正在使用这种方式的时候,我们什么也不需要做。这也是我们以后比较常用的一种方式。

(2)静态工厂

在spring的配置文件application.properties中添加以下内容:

<bean id="orderDao" class="com.mytest.factory.OrderDaoFactory" factory-method="getOrderDao"/>

class:工厂类的类全名

factory-mehod:具体工厂类中创建对象的方法名

在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,这些操作必不可少,比如日志等业务操作。

具体实现代码略,这种方式一般是用来兼容早期的一些老系统,所以了解为主。

(3)实例工厂(FactoryBean)

实例工厂实例化配置的过程还是比较复杂,所以spring为了简化这种配置方式就提供了一种叫 FactoryBean的方式来简化开发。

创建一个UserDaoFactoryBean的类,实现FactoryBean接口,重写接口的方法

public class UserDaoFactoryBean implements FactoryBean<UserDao> { //代替原始实例工厂中创建对象的方法 public UserDao getObject() throws Exception { return new UserDaoImpl(); } //返回所创建类的Class对象 public Class<?> getObjectType() { return UserDao.class; } }

在Spring的配置文件中进行配置,之后AppForInstanceUser运行类不用做任何修改,直接运行即可。

<bean id="userDao" class="com.mytest.factory.UserDaoFactoryBean"/>

查看源码会发现,FactoryBean接口其实会有三个方法,分别是:

//方法一:getObject(),被重写后,在方法中进行对象的创建并返回 T getObject() throws Exception; //方法二:getObjectType(),被重写后,主要返回的是被创建类的Class对象 Class<?> getObjectType(); //方法三:默认单例,将return重写false即可改成非单例 default boolean isSingleton() { return true; }

这些方式中,重点掌握构造方法和FactoryBean即可。

需要注意的一点是,构造方法在类中默认会提供,但是如果重写了构造方法,默认的就会消失,在使 用的过程中需要注意,如果需要重写构造方法,最好把默认的构造方法也重写下。


四、依赖注入高级技巧

0.相关属性

1. 集合注入

<!-- List注入 --> <property name="list"> <list> <value>Java</value> <ref bean="obj1"/> <!-- 引用其他Bean --> </list> </property> <!-- Map注入 --> <property name="map"> <map> <entry key="port" value="8080"/> <entry key="db" value-ref="dataSource"/> </map> </property>
  • property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签
  • List的底层也是通过数组实现的,所以<list>和<array>标签是可以混用
  • 集合中要添加引用类型,只需要把<value>标签改成<ref>标签,这种方式用的比较少

2. 解决依赖冲突

  • 按类型自动装配:容器中同类型Bean必须唯一

  • 按名称装配:属性名需与Bean的id匹配(耦合度高,慎用)


五、小结

(1)什么IOC/DI思想?

  • IOC:控制反转,控制反转的是对象的创建权
  • DI:依赖注入,绑定对象与对象之间的依赖关系

(2)什么是IOC容器?

  • Spring创建了一个容器用来存放所创建的对象,这个容器就叫IOC容器

(3)什么是Bean?

  • 容器中所存放的一个个对象就叫Bean或Bean对象。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询