Rhythmli's blog Rhythmli's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Rhythmli

知识就是财富
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 技术文档

  • GitHub技巧

  • Nodejs

  • 博客搭建

  • CSDN迁移

    • Spring IOC
      • Ngnix 阿里云
      • 最长回文子串
      • 面试题xuexixiexue
      • 哈希集合和哈希映射的简单设计
      • leetcode2021.11.03
      • Leetcode2021.11.2
      • JUC学习
      • 869. 重新排序得到 2 的幂
      • Java自动装箱拆箱
      • 55. 跳跃游戏
      • 剑指 Offer II 085. 生成匹配的括号
      • 300. 最长递增子序列
      • Java并发编程之美 01
      • 134. 加油站
      • 139. 单词拆分
      • 岛屿类问题题解
      • 138. 复制带随机指针的链表
      • 347. 前 K 个高频元素
      • 剑指 Offer II 026. 重排链表
      • 剑指 Offer II 025. 链表中的两数相加
      • 剑指 Offer II 014. 字符串中的变位词
      • 剑指 Offer II 010. 和为 k 的子数组
      • 剑指 Offer II 009. 乘积小于 K 的子数组
      • 剑指 Offer II 008. 和大于等于 target 的最短子数组
      • 剑指 Offer II 007. 数组中和为 0 的三个数
      • 剑指 Offer II 006. 排序数组中两个数字之和
      • 剑指 Offer II 002. 二进制加法
      • 129. 求根节点到叶节点数字之和
      • 113.路径总和 II
      • leetcode18. 四数之和
      • 编译OpenCV 以及 openc_contrib 提示缺少boostdesc_bgm.i文件出错的解决
      • fork()浅学习
      • SSM 增删改查
      • springmvc helloworld
      • Spring01 hello实验
      • 树的DFS和BFS
      • leetcode——二分法
      • Halo博客搭建
      • 计算机视觉领域的一些牛人博客,超有实力的研究机构等的网站链接---转载
      • opencv+python+OpenPose姿态实时识别
      • 03.KNN算法 李航统计学习方法
      • 02.感知机 李航统计学习方法
      • 01.最小二乘法拟合 李航统计学习方法
      • Pycharm atplotlib.pyplot图像不显示解决方法
      • 论文阅读01 SVM+kNN图像分类
      • Java简单实现计算器——用数组实现栈
      • 【剑指Offer3】无重复字符的最长子串
      • 【剑指Offer5】最长回文字符串
      • TF-IDF求取文本相似度
      • JAVA_day02
      • JAVA_day01
      • 递归产生回文数
      • 中国象棋QT登录注册以及悔棋功能
      • STM32F4学习笔记(基础介绍篇)
      • leetcode_04 递归,回溯与分治
      • leetcode03_贪心算法
      • leetcode01--链表
      • leetcode_02栈
      • Docker学习入门
      • C/C++编译与链接 程序员的自我修养:链接 装载和库
      • Nginx简单学习
      • JAVA网络编程
      • JVM初步学习
      • Spring简单学习
      • 标准项目格式
      • 设计模式中的几个原则
      • Redis和IDEA简单创建及增删改查
      • Mybatis快速入门01
      • Redis全程学习笔记(附带学习的视频教程)
      • QT入门学习中最基础的那些事儿
      • QT中文输出错误问题:C2001
      • OOP:面向对象编程
      • LINUX常用命令集合(待续)
      • 《C和指针》简单学习笔记
      • 二叉树,栈存储及遍历小程序
      • 数据结构简单学习笔记
      • 扑克牌
      • C++动态内存和智能指针
      • 设计模式之简单工厂模式
      • leetcode_01数组
      • 嵌入式Linux移植应用
      • LINUX 进程与线程 信号量 通信
    • 技术
    • CSDN迁移
    梁山话事人
    2026-03-31
    目录

    Spring IOC

    原文链接:https://blog.csdn.net/qq_39355828/article/details/159695228 (opens new window) 总要再读一次Spring IOC代码吧

    参考地址:https://javadoop.com

    # 1.环境准备

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.11.RELEASE</version>
    </dependency>
    
    1
    2
    3
    4
    5

    然后包被引入:

    image.png

    ApplicationContext context = new ClassPathXmlApplicationContext("");
    
    1

    image.png

    使用具体实现为ClassPathXmlApplicationContext,继承于ApplicationContext,父类引用指向子类。 首先,定义一个接口:

    public interface MessageService {
        String getMessage();
    }
    
    1
    2
    3

    定义接口实现类:

    public class MessageServiceImpl implements MessageService {
    
        public String getMessage() {
            return "hello world";
        }
    }
    
    1
    2
    3
    4
    5
    6

    接下来,我们在 resources 目录新建一个配置文件,文件名随意,通常叫 application.xml 或 application-xxx.xml 就可以了:

    <?xml version="1.0" encoding="UTF-8" ?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
    
        <bean id="messageService" class="com.javadoop.example.MessageServiceImpl"/>
    </beans>
    
    1
    2
    3
    4
    5
    6
    7

    这样,我们就可以跑起来了:

    public class App {
        public static void main(String[] args) {
            // 用我们的配置文件来启动一个 ApplicationContext
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
    
            System.out.println("context 启动成功");
    
            // 从 context 中取出我们的 Bean,而不是用 new MessageServiceImpl() 这种方式
            MessageService messageService = context.getBean(MessageService.class);
            // 这句将输出: hello world
            System.out.println(messageService.getMessage());
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 2.BeanFactory

    核心职责:

    • 根据 name
    • 或根据 type
    • 去“取一个 Bean” image.png

    image.png

    # 1.ListableBeanFactory

    ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean,大家看源码会发现,最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。
    
    1
    • getBeansOfType(…):拿到某个类型的所有 Bean
    • getBeanDefinitionNames():拿到所有 Bean 名称
    • getBeanNamesForType(…):拿到某种类型对应的所有 Bean 名称 image.png Spring 能拿到“某种类型对应的所有 Bean 名称”,本质上是因为容器内部保存了全部 Bean 的定义信息,然后在 DefaultListableBeanFactory 中遍历这些定义,逐个做类型匹配,最后把符合条 件的 beanName 收集起来。 image.png
    List<String> result = new ArrayList<>();
    
      for (String beanName : beanDefinitionNames) {
          BeanDefinition bd = beanDefinitionMap.get(beanName);
    
          if (bd.isAbstract()) {
              continue;
          }
    
          if (isTypeMatch(beanName, targetType)) {
              result.add(beanName);
          }
    
          // 如果是 FactoryBean,还要额外判断工厂本身/产品对象
      }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    # 2.HierarchicalBeanFactory

    ApplicationContext 继承了 HierarchicalBeanFactory,Hierarchical 单词本身已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。

    需要父子容器,本质上是为了“分层管理”和“复用 Bean”,避免所有 Bean 都堆在一个大容器里。

    比如一个大型应用里,不同模块关心的 Bean 不一样:

    • 父容器放公共 Bean:service、repository、数据源、事务管理器
    • 子容器放局部 Bean:某个 Web 模块自己的 controller、视图解析器、处理器映射器

    这样做的好处是:

    • 公共能力可以复用
    • 不同层的职责更清晰
    • 子容器可以访问父容器,父容器不用感知子容器
    • 方便模块隔离,避免所有 Bean 混在一起

    # 3.启动过程分析

    设置了类配置路径之后 其中最重要的是refresh方法

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            //初始化 BeanFactory、加载 Bean、注册 Bean 等等,查看类图,这里是个返回是个beanFactory
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);
    
            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
    
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }
    
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

    其中: ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    	//刷新BeanFactory 删除旧的 创建新的 BeanFactory
        this.refreshBeanFactory();
        //获取BeanFactory后进行返回
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
        }
    
        return beanFactory;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    ![[Pasted image 20260331111251.png]]

    protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }
    
        try {
    	    //ConfigurableListableBeanFactory 只有一个实现类 DefaultListableBeanFactory,而且实现类 DefaultListableBeanFactory 还通过实现右边的 AbstractAutowireCapableBeanFactory 通吃了右路。
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            this.loadBeanDefinitions(beanFactory);
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), ex);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    继续往下,看到:

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

    Bean加载时,将 xml 文件转换为 Document 对象

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            Document doc = this.doLoadDocument(inputSource, resource);
            return this.registerBeanDefinitions(doc, resource);
        } catch (BeanDefinitionStoreException ex) {
            throw ex;
        } catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        } catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex);
        } catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex);
        } catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex);
        } catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    转化为DOM树

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        this.logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
        this.doRegisterBeanDefinitions(root);
    }
    
    1
    2
    3
    4
    5
    6

    对Bean文件进行解析:

    String id = ele.getAttribute("id");
    String nameAttr = ele.getAttribute("name");
    List<String> aliases = new ArrayList();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
        aliases.addAll(Arrays.asList(nameArr));
    }
    
    1
    2
    3
    4
    5
    6
    7

    生成beanDefinition

    AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);

    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                } else {
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }
    
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                }
            } catch (Exception ex) {
                this.error(ex.getMessage(), ele);
                return null;
            }
        }
    
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    } else {
        return null;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

    生成后,进行注册

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    
            try {
    	        //bean进行注册
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException ex) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
            }
    
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    其中bdHolder 只包含了: BeanDefinition 的实例和它的 beanName、aliases 这三个信息 注册部分代码:

    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        String beanName = definitionHolder.getBeanName();
    	    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    	    //这里是要注册所有的别名,这样使用别名可以找回来
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for(String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    注册代码:

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    
    		// 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
             this.beanDefinitionMap.put(beanName, beanDefinition);
             // 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
             this.beanDefinitionNames.add(beanName);
             // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
             // 注意这里是 remove 方法,到这里的 Bean 当然不是手动注册的
             // 手动指的是通过调用以下方法注册的 bean :
             //     registerSingleton(String beanName, Object singletonObject)
             // 这不是重点,解释只是为了不让大家疑惑。Spring 会在后面"手动"注册一些 Bean,
             // 如 "environment"、"systemProperties" 等 bean,我们自己也可以在运行时注册 Bean 到容器中的
             this.manualSingletonNames.remove(beanName);
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    以上完成了Bean的注册

    继续向下:

    preInstantiateSingletons:
    
    for(String beanName : beanNames) {
        RootBeanDefinition bd = this.getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (this.isFactoryBean(beanName)) {
                final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);
                boolean isEagerInit;
                if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                    isEagerInit = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                        public Boolean run() {
                            return ((SmartFactoryBean)factory).isEagerInit();
                        }
                    }, this.getAccessControlContext());
                } else {
                    isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
                }
    
                if (isEagerInit) {
                    this.getBean(beanName);
                }
            } else {
                this.getBean(beanName);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    继续向下则是Bean的创建: ![[Pasted image 20260331160308.png]]

    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        } else if (mbd.getFactoryMethodName() != null) {
            return this.instantiateUsingFactoryMethod(beanName, mbd, args);
        } else {
            boolean resolved = false;
            boolean autowireNecessary = false;
            if (args == null) {
                synchronized(mbd.constructorArgumentLock) {
                    if (mbd.resolvedConstructorOrFactoryMethod != null) {
                        resolved = true;
                        autowireNecessary = mbd.constructorArgumentsResolved;
                    }
                }
            }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    属性注入:

    // bean 实例的所有属性都在这里了
       PropertyValues pvs = mbd.getPropertyValues();
       //...
       //然后先name 再type
    
    1
    2
    3
    4

    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

    // 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
    
      // 通过类型装配。复杂一些
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }
    
      pvs = newPvs;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    }

    然后是initializeBean 初始化,解决各种回调。
    
       区别非常关键:
    
      - populateBean:给 Bean “填属性”
      - initializeBean:对 Bean 做“初始化”
    
      它们是 Spring 创建 Bean 过程里的两个不同阶段。
    
      1. populateBean 是属性注入阶段
    
      这一阶段主要做:
    
      - 把 BeanDefinition 里的属性值设置到 Bean 实例上
      - 处理 @Autowired
      - 处理 @Value
      - 处理按名字、按类型自动注入
      - 调用 setter/反射完成依赖注入
    
      所以它关心的是:
    
      - 这个对象的成员变量、setter 属性,怎么补齐
    
      比如:
    
      userService.setOrderDao(orderDao);
      userService.setName("test");
    
      这些基本属于 populateBean 干的事。
    
      2. initializeBean 是初始化阶段
    
      属性都填完之后,Spring 才开始初始化 Bean。
    
      这一阶段主要做:
    
      - 调用 Aware 接口回调
      - 执行 BeanPostProcessor#postProcessBeforeInitialization
      - 调用初始化方法
      - 执行 BeanPostProcessor#postProcessAfterInitialization
    
      比如:
    
      - BeanNameAware
      - BeanFactoryAware
      - InitializingBean.afterPropertiesSet()
      - 自定义 init-method
      - AOP 代理生成,很多时候也发生在这里的后置处理器阶段
    
      所以它关心的是:
    
      - Bean 已经有完整依赖了,现在开始做“增强”和“初始化回调”
    
      3. 顺序上谁先谁后
    
      一般是:
    
      4. 实例化 Bean
      5. populateBean
      6. initializeBean
    
      也就是:
    
      - 先把对象造出来
      - 再把依赖注入进去
      - 最后再执行初始化逻辑
    
      4. 举个最直观的例子
    
      假设有个 Bean:
    
      public class UserService implements InitializingBean {
          private OrderDao orderDao;
    
          public void setOrderDao(OrderDao orderDao) {
              this.orderDao = orderDao;
          }
    
          @Override
          public void afterPropertiesSet() {
              System.out.println(orderDao); // 这里已经有值了
          }
      }
    
      Spring 会先执行:
    
      setOrderDao(...)
    
      这是 populateBean
    
      然后再执行:
    
      afterPropertiesSet()
    
      这是 initializeBean
    
      所以 afterPropertiesSet() 里看到的属性,通常已经注入完成了。
    
      5. 一句话抓本质
    
      populateBean 解决的是:
    
      - “把这个 Bean 需要的数据和依赖塞进去”
    
      initializeBean 解决的是:
    
      - “Bean 都准备好了,现在执行初始化回调和后置增强”
    
      一句话总结
    
      populateBean 是依赖注入、属性填充;initializeBean 是在属性注入完成之后,执行各种初始化回调和 Bean 后置处理。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    编辑 (opens new window)
    #CSDN
    上次更新: 2026/08/11, 13:36:18
    vdoing主题效果图
    Ngnix 阿里云

    ← vdoing主题效果图 Ngnix 阿里云→

    最近更新
    01
    Git修改分支名
    08-11
    02
    CSS给table的tbody添加滚动条
    06-29
    03
    33个非常实用的JavaScript一行代码
    11-02
    更多文章>
    Theme by Vdoing | Copyright © 2019-2026 Evan Xu | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式