小白学习笔记(spring框架ioc)

首先看下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配置:

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

  2. 思路

  3. 准备项目

    1. 创建maven工程(spring-ioc-xml-01)
    2. 导入SpringIoC相关依赖 pom.xml
    <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.0.6</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.3.1</version> </dependency> </dependencies>
  1. 基于无参数构造函数

当通过构造函数方法创建一个 bean(组件对象) 时,所有普通类都可以由 Spring 使用并与之兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定 Bean 类信息就足够了。但是,默认情况下,我们需要一个默认(空)构造函数。

    1. 准备组件类

    package com.atguigu.ioc;

    public class HappyComponent {

    复制代码
     //默认包含无参数构造函数
    
     public void doWork() {
         System.out.println("HappyComponent.doWork");
     }

    }

    1. xml配置文件编写

      创建携带spring约束的xml配置文件

      编写配置文件:

      文件:resources/spring-bean-01.xml

    <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent"/>
    复制代码
     - bean标签:通过配置bean标签告诉IOC容器需要创建对象的组件信息
     - id属性:bean的唯一标识,方便后期获取Bean!
     - class属性:组件类的全限定符!
     - 注意:要求当前组件类必须包含无参数构造函数!
  1. 基于静态工厂方法实例化

除了使用构造函数实例化对象,还有一类是通过工厂模式实例化对象。接下来我们讲解如何定义使用静态工厂方法创建Bean的配置 !

    1. 准备组件类

    public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

    public static ClientService createInstance() {

    复制代码
     return clientService;

    }
    }

    1. xml配置文件编写

      文件:resources/spring-bean-01.xml

    <bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>

    复制代码
     - class属性:指定工厂类的全限定符!
     - factory-method: 指定静态工厂方法,注意,该方法必须是static方法。
  1. 基于实例工厂方法实例化

接下来我们讲解下如何定义使用实例工厂方法创建Bean的配置 !

    1. 准备组建类

    public class DefaultServiceLocator {

    private static ClientServiceImplclientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
    return clientService;
    }
    }

    1. xml配置文件编写

      文件:resources/spring-bean-01.xml

    <bean id="serviceLocator" class="examples.DefaultServiceLocator"> </bean> <bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
    复制代码
     - 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注解使用:

相关推荐
arvin_xiaoting2 小时前
OpenClaw学习总结_I_核心架构_5:Memory系统详解
学习·系统架构·学习总结·ai agent·openclaw·memory系统
却道天凉_好个秋2 小时前
音视频学习(九十八):Profile
学习·音视频·profile
Kapibalapikapi2 小时前
操作笔记 | Ubuntu Server VMware虚拟机的文件传输
笔记·操作文档
shangjian0072 小时前
OpenClaw学习笔记-01-架构篇
笔记·学习·架构
少许极端2 小时前
算法奇妙屋(三十四)-贪心算法学习之路 1
学习·算法·贪心算法
551只玄猫2 小时前
【基于python的金融分析和风险管理 学习笔记】中阶篇 第6章 分析利率和汇率
笔记·python·学习·金融·学习笔记·汇率·利率
孤独的小丑2 小时前
OpenClaw学习资源汇编
汇编·学习
ljt27249606612 小时前
Flutter笔记--加水印
笔记·flutter
show2142 小时前
Memos 开源笔记的使用
笔记