宏观上看Spring创建对象的过程

宏观,spring,创建对象,过程 · 浏览次数 : 7

小编点评

**为什么还需要实现BeanPostProcessor接口为其增加功能呢?** 为了能够为多个对象增加功能,可以使用实现BeanPostProcessor接口的方式。BeanPostProcessor接口中的方法可以为多个对象增加功能,代码可以复用,减少代码的冗余。 **在BeanPostProcessor接口哪个方法为对象增加功能呢?** 在BeanPostProcessor接口的`postProcessAfterInitialization`方法中,我们可以为对象进行加工。 **其他问题解答** * 第5步的初始化操作,和BeanPostProcessor的方法,在开发中我们一般不用。 * Spring BeanFactory源码中是如何创建对象的BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(\"\"));beanFactory.getBean("id\");第一行代码的作用:读取xml文件,解析bean标签,封装成BeanDefinition对象,并以id为key,BeanDefinition对象为value存储到map中。

正文

宏观上看Spring创建对象的过程

对于对象而言,可以分为简单对象复杂对象

  • 简单对象

    简单对象指可以直接new的对象;
    Spring在创建这些对象时,是基于反射来完成的。
    
  • 复杂对象

    复杂对象指不能直接new的对象。
    比如:要得到接口类型的对象,是不能直接new的,需要使用其实现类来创建。但是有的其实现类也是不能直接new的,比如Connection对象。
    对于这种对象,可以使用实现FactoryBean接口的方式来创建;
    	需要实现三个方法:
    	getObject()   ------>  书写位置 ----->  Spring工厂 回调 getObject()获得对象
        getObjectType()
        isSingleton()
    也可以使用静态工厂或者实例工厂来创建;
    静态工厂:
        MyFactory{
             public static Object getObject(){
                     xxxx
                     xxxxx
              }
    
        }
        <bean id="" class="xxx.MyFactory"  factory-method="getObject"/>  
    
    实例工厂:
    	MyFactory{
        	public Object getObject(){}
    	}
    
        <bean id="myFactory" class="xxx.MyFactory"/>
    
        <bean id="product"  factory-bean="myFactory" factory-method="getObject"/>
    
    

    这仅仅完成了对象的创建。我们还要考虑为对象属性进行赋值(也称为属性的注入)。

Spring为创建的对象注入属性

注入的方式:

  • set注入

    <bean id="u" class="">
            <property > ----------set注入
    </bean>
    

    会有两种注入的形式

    • 程序员自己完成的注入

      可以注入8种基本类型、自建类型(通过ref=)的bean;

    • Spring容器自己的注入(aware)

      实现BeanNameAware接口,实现void setBeanName(String name)方法,Spring容器自动调用它【谁调用谁就会传参】,可以获取当前对象在工厂中的id(beanName),定义一个变量把它存起来就可以了;
      实现BeanFactoryAware接口,实现void setBeanFactory(BeanFactory beanFactory)方法,Spring容器自动调用它,可以获取创建当前对象的工厂对象,定义一个变量把它存起来就可以了。
      	BeanFactoryAware接口的应用场景:
      	可以解决scope=prototype在注入过程中失效的问题。
      	
      	比如类A是单例的,类B是多例的,类A中有类B的成员变量b,如果用set注入,每一次获取都是一样的地址,因为类A对象已经被创建出来,并存储到容器里了,再获取成员变量b时,没有为其重新赋值。
      	我们可以获取到工厂,每次在a中使用b时,都从容器中获取一次。
      scope=prototype在注入过程中失效的解决方式还有一个,lookup-method = ,但是用的少
      

      这两种方式先后顺序是怎样的呢?——用户自己设置的set注入在前,容器的注入在后。

  • 构造注入

    <bean id="u" class="">
            <constructor-arg >——————构造注入
    </bean>
    
  • autowire自动注入

    如果在beans配置,beans管理的所有bean都会自动注入

    beans自动注入

    如果在bean配置,此bean的属性会自动注入;

    自动注入

工厂创建对象的完整流程

宏观上看Spring创建对象的过程

  1. Spring工厂创建对象;
  2. 对属性进行set注入(用户的set注入在前,实现Aware接口容器的set注入在后);
  3. set注入完成后得到的对象交给BeanPostProcessor中的postProcessBeforeInitialization(Object bean, String beanName)方法为对象进行加工(参数bean就是待加工的bean,返回值为加工好的bean);
  4. 为postProcessBeforeInitialization方法加工后的对象进行初始化,有两种方式: 第一种方式实现InitializingBean接口(在前)、第二种方式 指定init-method方法(在后);
  5. 初始化后的对象,交给BeanPostProcessor中的postProcessAfterInitialization(Object bean, String beanName)方法为对象进行加工(参数bean就是待加工的bean,返回值为加工好的bean);
  6. 最后得到加工好的对象,用户可以进行使用;
  7. 工厂调用destroySingletons()方法,工厂关闭,销毁对象。

问题:为什么还需要实现BeanPostProcessor接口为其增加功能,不能在创建对象时,直接写好呢?

答案:BeanPostProcessor接口中的方法,可以为多个对象增加功能,代码可以复用,减少代码的冗余;

加功能是可有可无的功能,如果需要可以加上,如果不需要就取消掉,可以解决代码的耦合。

问题:一般在BeanPostProcessor接口的哪个方法为对象增加功能呢?

答案:postProcessAfterInitialization方法,因为前面已经初始化完成了,后续没有在对bean的操作了;如果在postProcessBeforeInitialization中为对象进行加工,后续可能还会改。

注意:BeanPostProcessor的功能,只有在高级的工厂(比如ApplicationContext)才有。

注意:第5步的初始化操作,和BeanPostProcessor的方法,在开发中我们一般不用。

Spring BeanFactory源码中是如何创建对象的

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(""));
beanFactory.getBean("id");

第一行代码的作用:

读取xml文件,解析bean标签,封装成BeanDefinition对象,并以id为key,BeanDefinition对象为value存储到map中;

第二行代码的作用:

1.基于BeanDefinition创建对象;
2.创建对象的过程,包括前文生命周期中除销毁的步骤;
3.创建对象的过程中,需要按照scope进行讨论:
	scope=singleton——单例对象,Spring中使用map结构(key为bean的id,value为bean)来保证永远只创建一次;
	scope=prototype——每次都走一遍创建对象的流程。

与宏观上看Spring创建对象的过程相似的内容:

宏观上看Spring创建对象的过程

# 宏观上看Spring创建对象的过程 对于对象而言,可以分为**简单对象**和**复杂对象**; - 简单对象 ```markdown 简单对象指可以直接new的对象; Spring在创建这些对象时,是基于反射来完成的。 ``` - 复杂对象 ```markdown 复杂对象指不能直接new的对象

《吐血整理》高级系列教程-吃透Fiddler抓包教程(34)-Fiddler如何抓取微信小程序的包-上篇

1.简介 有些小伙伴或者是童鞋们说小程序抓不到包,该怎么办了???其实苹果手机如果按照宏哥前边的抓取APP包的设置方式设置好了,应该可以轻松就抓到包了。那么安卓手机小程序就比较困难,不是那么友好了。所以今天宏哥重点说一下安卓手机小程序抓包。 2.前言 首先看下是否满足以下条件小程序无法抓包原因 :

架构师日记-从代码到设计的性能优化指南 | 京东云技术团队

性能优化是个系统性工程,宏观上可分为网络,服务,存储几个方向,每个方向又可以细分为架构,设计,代码,可用性,度量等多个子项。 本文将重点从代码和设计两个子项展开,谈谈那些提升性能的知识点。

《最新出炉》系列初窥篇-Python+Playwright自动化测试-2-playwright的API及其他知识

1.简介 上一篇宏哥已经将Python+Playwright的环境搭建好了,而且也简单的演示了一下三款浏览器的启动和关闭,是不是很简单啊。今天主要是把一篇的中的代码进行一次详细的注释,然后说一下playwright的API和其他相关知识点。那么首先将上一篇中的代码进行一下详细的解释。 2.代码解释

《最新出炉》系列入门篇-Python+Playwright自动化测试-41-录制视频

1.简介 上一篇讲解和分享了录制自动生成脚本,索性连带录制视频也一股脑的在这里就讲解和分享了。今天我们将学习如何使用Playwright和Python来录制浏览器操作的视频,以便在需要时进行回放和分析。 2.录制视频语法 录制视频介绍官方API的文档地址:https://playwright.dev

《吐血整理》高级系列教程-吃透Fiddler抓包教程(32)-Fiddler如何抓取IOS系统中Flutter应用程序的包

1.简介 上一篇讲解了安卓手机可以通过VPN代理来抓取Flutter应用程序的包,iOS(iphone)同样使用上一篇中VPN方法(原理与android是一致的),同样需要使用到VPN,在iOS也有许多与drony功能类似的软件,大家可以自己选择自己喜欢的使用,宏哥这里使用的是Shadowrocke

《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(2)-charles安装激活(Mac)最新简单教程【亲测有效】

1.简介 上一篇中宏哥介绍了如何在Windows系统安装激活Charles,那么使用Mac系统的小伙伴或者童鞋们就不高兴了,怎么没有Mac的安装激活教程了。宏哥不能厚此薄彼,今天专门补充一篇在Mac上安装Charles并且将其激活。 2.Mac下载安装 2.1下载Charles 官网下载:https

《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(3)-再识Charles

1.简介 上一篇通过宏哥的介绍想必各位小伙伴或者童鞋们对Charles已经有了一个理性地认识,今天宏哥在从Charles的外貌介绍和分享一下,让小伙伴们或者童鞋们再对Charles有一个感性的认识,今天主要是对Charles的界面进行一个详细的介绍。 2.Charles主界面概览 Charles的主

《最新出炉》系列初窥篇-Python+Playwright自动化测试-6-元素定位大法-下篇

1.简介 上一篇主要是讲解我们日常工作中在使用Playwright进行元素定位的一些比较常用的定位方法的理论基础知识以及在什么情况下推荐使用。今天这一篇讲解和分享一下,在日常中很少用到或者很少见的定位,但是遇到了我们也要会,俗话说:手里有粮心里不慌。 2.阴影定位-Shadow DOM 在做web自

《最新出炉》系列入门篇-Python+Playwright自动化测试-7-浏览器的相关操作

1.简介 上一篇已经将playwright的元素定位大法基本介绍的差不多了,但是在Web的UI自动化的测试中,我们通常需要使用一些方法来操作浏览器,今天就跟随学习了解一下。这一篇宏哥主要是介绍一下,在自动化测试的时候,我们常见的一些浏览器操作有哪些,宏哥将会一一介绍和讲解。 2.层级 在介绍浏览器的