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

智数觅云人
• 阅读 242

宏观上看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都会自动注入

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

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

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

工厂创建对象的完整流程

宏观上看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——每次都走一遍创建对象的流程。
点赞
收藏
评论区
推荐文章
小万哥 小万哥
1年前
C++编程必备:对象生命周期管理的最佳实践
在C中,对象的生命周期是指对象存在的时间段,从对象创建到对象销毁的整个过程。正确地管理对象的生命周期是编写高效、可靠C代码的关键之一。
浩浩 浩浩
5年前
JVM--对象创建过程
类创建总结根据new的参数在常量池种寻找一个类的符号引用,如果类没有被加载,则进行类加载、解析、初始化。<cinit
九路 九路
5年前
2 Java对象的创建过程
JAVA中创建对象直接new创建一个对象,对么对象的创建过程是怎样的呢?程序运行过程中有许多的对象被创建出来.那么对象是如何创建的呢?一对象创建的步骤1遇到new指令时,检查这个指令的参数是否能在常量池中找到一个符号引用2如果找到符号引用,就检查这个符号引用是否已经被加载,解析和初始化过3如果没有加载过,则执行类加载过程
Wesley13 Wesley13
4年前
Java项目笔记之知识点总结03
不点蓝字,我们哪来故事?SSM本质是Spring去集成SpringMVC和MyBatis,即控制器对象、业务对象、Mapper对象等都交由Spring容器管理,使用SpringIoC和DI来完成对象创建及其属性注入,使用AOP来配置事务。作用是在框架上基础上开发,发挥各
Stella981 Stella981
4年前
Spring3.1.0实现原理分析(八).获取bean对象
   Spring获取bean对象的逻辑相对简单,原本不打算专门写篇博客来介绍了。不过想了想,既然上两篇博客分析了Spring创建对象的过程,有创建便有获取,所以还是分析下获取bean对象的过程吧。一.获取单例bean1).进入DefaultSingletonBeanRegistry的getSingleton方法,下面是代码片段,简单
Stella981 Stella981
4年前
Django框架详细介绍
一、概述    ORM(ObjectRelationalMapping),全称:对象关系映射,简单的说就是通过创建类、实例化出对象的方法,使得类、对象、对象的属性能够和数据库中的表、记录、字段意义对应。  ORM只是一种工具,避免了开发人员在开发过程中不用反复地编写大量复杂的SQL语句,而可以专注于业务逻辑上的开发,提高开发效率,但是OR
Wesley13 Wesley13
4年前
Unity 获取场景中所有目标对象(包括不激活的对象)
usingUnityEngine;usingUnityEditor;usingSystem.Collections.Generic;publicclassExampleScript:MonoBehaviour{//获取场景中所有目标对象(包括不激活的对象)不包括Pre
Wesley13 Wesley13
4年前
JS篇(004)
答案:1.脚本语言。JavaScript是一种解释型的脚本语言,C、C等语言先编译后执行,而JavaScript是在程序的运行过程中逐行进行解释。2.基于对象。JavaScript是一种基于对象的脚本语言,它不仅可以创建对象,也能使用现有的对象。3.简单。JavaScript语言中采用的是弱类型的变量
Stella981 Stella981
4年前
JSP内置九个对象Request请求对象
jsp内置对象是什么呢?例如Java语言使用一个对象之前需要实例化(也就是所说的new一个对象),创建对象这个过程有点麻烦,所以在jsp中提供了一些内置对象,用来实现很多jsp应用。在使用内置对象时,不需要实例化这些对象,直接使用就行了。预先定义了九个这样的对象。下面分别对这九个预先定于的对象进行分析和讲解。1.Request请求对象
Wesley13 Wesley13
4年前
C++ 常用设计模式(学习笔记)
设计模式1、工厂模式在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。工厂模式作为一种创建模式,一般在创建复杂对象时,考虑使用;在创建简单对象时,建议直接new完成一个实例对象的创建。1.1、简单工厂模式主要特点是需要在工厂类中做判断,从而创造相应的产品,当
Wesley13 Wesley13
4年前
09面向对象高级特性二
面向对象高级特性二上转型对象(上溯)如果A类是B类的父类,当我们用子类创建对象,并把这个对象的引用放到父类的对象中时:Aa;BbnewB();     或        AanewB();ab;称父类对象a是子类对象b的上转型对象。上转型对象