首先看下spring全家桶之间的关系:


Spring-ioc容器:
组件:

组件的专业定义
Spring 中的组件(Component) 本质是:
被 Spring IoC 容器创建、管理、销毁的 Java 对象(也常被称为 "Bean",Bean 是更通用的叫法,Component 是标记组件的核心注解)。
简单说:只要一个 Java 类被 Spring 的特定注解标记,它就会被 Spring 容器识别并自动实例化,成为 Spring 管理的组件。
简单来说就是:spring框架new出来的对象就是组件,而这些组件我们加了注释之后就可以直接使用
IoC容器:

容器的专业定义
Spring 核心容器是 Spring 框架的最底层、最核心的模块 ,是实现IoC(控制反转) 思想的核心载体,它的核心职责是:
负责扫描、解析、创建、配置、管理、销毁所有 Spring 组件(Bean),并实现组件之间的依赖注入(DI),是所有 Spring 功能(比如 AOP、SpringMVC)的基础。
简单来说就是管理组件的地方

容器的接口和实现类:


配置文件的方法:

Ioc容器和di:

ioc:指的是原本是由程序员来创建对象的,现在由容器来控制这些,所以叫控制反转。所以容器也叫ioc容器
di:依赖注入,只需要在配置文件中告诉对象之间的关系,容器就能自动的把对象注入到别的对象之中。
Spring IoC和di的实现步骤:

基于XML的ioc配置:
-
目标 Spring IoC 容器管理一个或多个 bean。这些 Bean 是使用您提供给容器的配置元数据创建的(例如,以 XML
<bean/>定义的形式)。 我们学习,如何通过定义XML配置文件,声明组件类信息,交给 Spring 的 IoC 容器进行组件管理! -
思路

-
准备项目
-
- 创建maven工程(spring-ioc-xml-01)
- 导入SpringIoC相关依赖 pom.xml
-
基于无参数构造函数
当通过构造函数方法创建一个 bean(组件对象) 时,所有普通类都可以由 Spring 使用并与之兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定 Bean 类信息就足够了。但是,默认情况下,我们需要一个默认(空)构造函数。
-
- 准备组件类
package com.atguigu.ioc;
public class HappyComponent {
//默认包含无参数构造函数 public void doWork() { System.out.println("HappyComponent.doWork"); }}
-
xml配置文件编写
创建携带spring约束的xml配置文件

编写配置文件:
文件:resources/spring-bean-01.xml
- bean标签:通过配置bean标签告诉IOC容器需要创建对象的组件信息 - id属性:bean的唯一标识,方便后期获取Bean! - class属性:组件类的全限定符! - 注意:要求当前组件类必须包含无参数构造函数! -
基于静态工厂方法实例化
除了使用构造函数实例化对象,还有一类是通过工厂模式实例化对象。接下来我们讲解如何定义使用静态工厂方法创建Bean的配置 !
-
- 准备组件类
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}public static ClientService createInstance() {
return clientService;}
}-
xml配置文件编写
文件:resources/spring-bean-01.xml
<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>
- class属性:指定工厂类的全限定符! - factory-method: 指定静态工厂方法,注意,该方法必须是static方法。 -
基于实例工厂方法实例化
接下来我们讲解下如何定义使用实例工厂方法创建Bean的配置 !
-
- 准备组建类
public class DefaultServiceLocator {
private static ClientServiceImplclientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}-
xml配置文件编写
文件:resources/spring-bean-01.xml
- factory-bean属性:指定当前容器中工厂Bean 的名称。 - factory-method: 指定实例工厂方法名。注意,实例方法必须是非static的!
xml配置文件:
<!--可以使用无参数构造函数实例化自动组件,如何进行配置
<bean> 代表一个组件信息,一个组件对象
id 组件的标识, 唯一 ,方便后期读取
class 组建的类的全限定符
-->
<bean id="happyComponent1" class="com.atguigu.ioc_01.HappyComponent"/>
<bean id="happyComponent2" class="com.atguigu.ioc_01.HappyComponent"/> <!--将一个组件类,生命两个组件信息,默认是单例模式,会实例化两个对象-->
<!--静态工厂类如何声明工厂方法进行ioc配置
bean 标签
id :组件的标识
class : 工厂类的全限定符
factory-method : 静态工厂方法
-->
<bean id="clientService" class="com.atguigu.ioc_01.ClientService" factory-method="createInstance" />
<!--非静态工厂如何声明ioc配置-->
<!--3.1 配置工厂类的组件信息-->
<bean id="defaultServiceLocator" class="com.atguigu.ioc_01.DefaultServiceLocator"/>
<!--3.2 通过指定非静态工厂对象和方法名 来配置生成的ioc信息-->
<bean id="clientService" factory-bean="defaultServiceLocator" factory-method="createClientServiceInstance"/>
</beans>
基于xml的di配置:
通过构造函数方法依赖注入:
两个实体类:
public class UserService {
private UserDao userDao;
public UserService() {
}
public UserService(UserDao userDao) {
this.userDao = userDao;
}
private int age;
private String name;
public UserService(int age,String name,UserDao userDao) {
this.userDao = userDao;
this.age = age;
this.name = name;
}
}
public class UserDao {
}
xml配置文件:
<!--引用和被引用的组件 必须全部放在ioc容器里-->
<!--1.单个构造参数注入-->
<!--步骤1:把他们都存放在ioc容器中-->
<bean id="userDao" class="com.atguigu.ioc_02.UserDao"/>
<bean id="userService" class="com.atguigu.ioc_02.UserService">
<!--构造参数传值 di的配置-->
<!--constructor-arg 构造参数传值的di配置
value 是直接属性值 int age = 18
ref 是引用其他的bean ,里面直接写beaId值
-->
<constructor-arg ref="userDao"/>
</bean>
<!--多个构造参数注入-->
<bean id="userService1" class="com.atguigu.ioc_02.UserService">
<!--方式1:构造参数的顺序填写值-->
<constructor-arg value="18" />
<constructor-arg value="妄竹"/>
<constructor-arg ref="userDao"/>
</bean>
<bean id="userService1" class="com.atguigu.ioc_02.UserService">
<!--方式2:构造参数的name写值-->
<constructor-arg name="age" value="18" />
<constructor-arg name="name" value="妄竹"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
<bean id="userService2" class="com.atguigu.ioc_02.UserService">
<!--方式3:构造参数的参数下角标指定填写,不用考虑顺序,index = 构造参数的下角标 从左到右,从0开始-->
<!-- age = 0 name = 1 userDao = 2-->
<constructor-arg index="1" value="妄竹"/>
<constructor-arg index="0" value="18" />
<constructor-arg index="2" ref="userDao"/>
</bean>
通过setter方法依赖注入:
两个实体类:
public class MovieFinder {
}
public class SimpleMovieLister {
private MovieFinder movieFinder;
private String movieName;
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
public void setMovieName(String movieName) {
this.movieName = movieName;
}
}
xml配置文件:
<!--触发setter方法进行注入-->
<bean id="movieFinder" class="com.atguigu.ioc_02.MovieFinder"/>
<bean id="simpleMovieLister" class="com.atguigu.ioc_02.SimpleMovieLister">
<!--
property 标签 用于setter方法注入
name :填的就是setter方法名,但是把set去掉
value | ref 二选一 :value:直接属性值 ref:其他bean的Id
-->
<property name="movieName" value="寻梦环游记"/>
<property name="movieFinder" ref="movieFinder"/>
</bean>
ioc容器的创建和使用:
public class SpringIoCTest {
//如何创建ioc容器并且读取配置文件
public void createIoC(){
//方式1:直接创建容器并且指定配置文件即可
//构造函数(String...配置文件)可以填写一个或者多个
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-03.xml");
//方式2:先创建ioc容器对象,再指定配置文件,再刷新
方式二:

使用:
//如何在ioc容器中获取组件bean
//1. 创建ioc容器对象
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setConfigLocations("spring-03.xml");
applicationContext.refresh();
//2.读取ioc容器的组件
//方案1:直接根据beanId获取即可 返回值类型是Object ,需要强转,不推荐
HappyComponent happyComponent = applicationContext.getBean("happyComponent");
//方案2:根据beanId,同时指定bean的类型Class
HappyComponent happyComponent1 = applicationContext.getBean("happyComponent",HappyComponent.class);
//方案3:直接根据类型获取
/*
注意:
根据bean的类型获取,同一个类型,在ioc容器中只能有一个bean
如果ioc容器存在多个同类型的bean 会出现:NoUniqueBeanDefinitionException
ioc的配置一定是实现类,但是可以根据接口类型获取值
*/
HappyComponent happyComponent2 = applicationContext.getBean(HappyComponent.class);
happyComponent2.dowork();
}
组件作用域和周期方法配置:
周期方法:
实体类:
public class JavaBean {
/**
* 必须是public 必须是void返回值 必须是无参数的
* 命名随意
* 什么方法 ->写对应的方法逻辑就行
*/
public void init(){
System.out.println("init");
}
public void clear(){
System.out.println("clear");
}
}
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--init-method : 指定初始化方法名
destroy-method : 销毁方法名
spring ioc 容器就会在对应的时间触发周期函数
-->
<bean id="javaBean" class="com.atguigu.ioc_04.JavaBean" init-method="init" destroy-method="clear"/>
</beans>
测试:
/**
* 测试ioc配置和销毁方法的触发
*/
public void test04(){
//1.创建ioc容器 就会进行组件对象的实例化 -> init
ClassPathXmlApplicationContext applicationContext1 = new ClassPathXmlApplicationContext("spring-04.xml");
//2.正常结束ioc容器
applicationContext.close();
}
作用域配置:


测试:

配置信息里的scope默认是singleton,单例的话就只会创建一个bean 对象,如果是多例,就会创建多个bean对象。
高级特性:FactoryBean特性和使用:


factorybean的使用:
组件类:
public class JavaBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
组件类的factorybean:
public class JavaBeanFactoryBean implements FactoryBean<JavaBean> {
@Override
public JavaBean getObject() throws Exception {
//使用自己的方式实例化对象
JavaBean javaBean = new JavaBean();
return javaBean;
}
@Override
public Class<?> getObjectType() {
return JavaBean.class;
}
}
xml配置文件:
<!--
id : getObject方法返回的对象的标识
class:factoryBean标准化工厂类
-->
<bean id="javaBean" class="com.atguigu.ioc_05.JavaBeanFactoryBean" />
</beans>
测试代码:
public void test05(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-05.xml");
//读取组件
//这个是拿到实例化对象
JavaBean javaBean = applicationContext.getBean("javaBean", JavaBean.class);
System.out.println(javaBean);
//这个是拿到工厂类
Object bean = applicationContext.getBean("&javaBean");
System.out.println(bean);
applicationContext.close();
}
}
基于注解方式的ioc配置:
流程:
1.先标记注解
2.再配置指定包(告诉spring要扫描哪些包)

测试:
几个组件类:
package com.atguigu.ioc_01;
import org.springframework.stereotype.Component;
/**
* ClassName:CommonComponent
* Package:com.atguigu.ioc_01
* Description:
*
* @Author 妄汐霜
* @Create 2026/3/20 16:58
* @Version 1.0
*/
@Component //这个注解的作用相当于<bean id = "commonComponent" class = "CommonComponent"
public class CommonComponent {
}
@Controller
public class XxxController {
}
@Repository
public class XxxDao {
}
@Service
public class XxxService {
}
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--普通配置包扫描-->
<!--
base-package:指定ioc容器去哪些包下查找注解类,然后把这些注解类放进ioc容器中
可以指定一个包或者多个包:比如:com.atguigu.x,com.atguigu.y 包和包之间用,隔开
指定包就相当于指定了包内的所有类
-->
<context:component-scan base-package="com.atguigu.ioc_01"/>
<!--指定包,但是排除注解-->
<context:component-scan base-package="com.atguigu.ioc_01">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--指定包,指定包含注解
指定包下的所有注解都生效
-->
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!--只扫描包下的注解-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
</beans>
测试类:
public class SpringIoCTest {
private static final Log log = LogFactory.getLog(SpringIoCTest.class);
@Test
public void testIoC_01(){
//1.创建ioc容器
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-01.xml");
//2.获取组件
XxxDao bean = applicationContext.getBean(XxxDao.class);
System.out.println(bean);
//添加ioc注解,默认的组件名为 类的首字母小写!
Object bean1 = applicationContext.getBean("xxxService");
System.out.println(bean1);
//3.close容器
applicationContext.close();
}
}

组件作用域和周期方法注解:
周期方法:
@Component //<bean id=javaBean class = "JavaBean">
public class JavaBean {
//周期方法命名随意,但是必须是public void 而且必须没有形参
@PostConstruct //初始化方法的注解
public void init(){
}
@PreDestroy
public void destroy(){
}
}
作用域:

标签声明:
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)//多例
//@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON)//单例
@Component //<bean id=javaBean class = "JavaBean">
public class JavaBean {
//周期方法命名随意,但是必须是public void 而且必须没有形参
@PostConstruct //初始化方法的注解
public void init(){
}
@PreDestroy
public void destroy(){
}
}
di注入注解语法:
自动注入依赖的好处就是不用自己创建实例了,spring容器会创建,直接用就好。
测试:
三个实体类:
@Controller
public class SoliderController {
@Autowired
private SoliderService soliderService;
public void getMessage(){
soliderService.gerMessage();
}
}
@Service
public class SoliderService {
@Autowired
private SoliderDao soliderDao;
public void gerMessage(){
soliderDao.getMessage();
}
}
@Repository
public class SoliderDao {
public void getMessage(){
System.out.println("i am a solider");
}
}
设定:SoliderController需要SoliderService,SoliderService需要SoliderDao
@Controller这个标签是把这些类放进ioc容器中,让容器来管
@Autowired这个标签的意思就是告诉ioc容器需要哪个类的对象,让它造好,我们直接用就行
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.atguigu.ioc_03"/>
</beans>
测试代码:
@Test
public void testIoC_02(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-03.xml");
SoliderController solider = applicationContext.getBean(SoliderController.class);
solider.getMessage();
applicationContext.close();
}
佛系装配:

如果有多个同类型的bean时,要怎么注入?
方法一:

qualifier必须和autowired一起用,不能单独使用qualifier
方法二:

如果要用resource的话就必须导入一个依赖:
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
@value标签主要用于赋基本类型的值,或者读取外部配置
实体类:
@Component
public class JavaBean {
//@value 的作用:主要是为了直接赋值和读取外部文件的配置
@Value("${jdbc.username}")
private String username;
@Value("jdbc.password")
private String password;
}
xml配置文件:
<context:component-scan base-package="com.atguigu.ioc_04"/>
<context:property-placeholder location="classpath:jdbc.properties"/>
完全注解类开发:
完全注解类开发就是创建一个注解类用来代替xml文件的方式
注解类:
package com.atguigu.ioc_01.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* ClassName:JavaConfiguration
* Package:com.atguigu.ioc_01.config
* Description:
* config包下的是java的配置类,用来替代xml配置文件,实现完全注解开发
* 1.包扫描注解配置
* 2.引用外部的配置文件
* 3.声明第三方依赖的bean组件
*
*
* 步骤一:添加@configuration标签,代表是配置类
* 步骤二:实现上面的三个功能注解
*
* @Author 妄汐霜
* @Create 2026/3/21 19:29
* @Version 1.0
*/
@ComponentScan({"com.atguigu.ioc_01","com.atguigu.ioc_02"})
@PropertySource(value = "classpath:jdbc.properties")
@Configuration
public class JavaConfiguration {
}
两个组件类:
@Controller
public class StudentController {
}
@Service
public class StudentService {
}
测试:
public class SpringIoCTest {
private static final Log log = LogFactory.getLog(SpringIoCTest.class);
@Test
public void test(){
//1.创建ioc容器
//方法一
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfiguration.class);
//方法二
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(JavaConfiguration.class);
annotationConfigApplicationContext.refresh();//刷新
//获取bean
StudentController bean = applicationContext.getBean(StudentController.class);
System.out.println(bean);
}
}
@Bean标签的作用:
@Bean最常用的场景是注册第三方类(你理解的这个),但不是唯一作用;- 它的核心价值是自定义 Bean 的创建逻辑(比如传参、初始化、动态选择);
@Component管 "自动创建",@Bean管 "手动创建",两者互补。
@Bean必须和@Configuration一起用。
@ComponentScan({"com.atguigu.ioc_01","com.atguigu.ioc_02"})
@PropertySource(value = "classpath:jdbc.properties")
@Configuration
public class JavaConfiguration {
//导入第三方依赖的方法
/**
* <bean> 一个方法
* 方法的返回值类型 就是 bean组件的类型或者它的接口和父类
* 方法的名字 就是 bean id
* 方法体中自定义实现过程即可
* 最重要的一步 加上@Bean 会真正让配置类的方法创建的组件存储到ioc容器中
*
*/
@Bean
public DruidDataSource dataSource(){
//实现具体的实例化过程
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("abc123");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
}
名称指定:

周期方法设置:

作用域:(单例还是多例)

如何引用其他ioc组件:
方案一:

方案二:

方案二就是在形参列表中写多个就可以导入多个,但是必须要存在,不然就会报错
@Import注解使用:


