Bean的创建过程源码

一、概念

Bean创建的流程图
在这里插入图片描述

Bean的创建生命周期
UserService.class —> 无参构造方法—>普通对象—>依赖注入(属性赋值、BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口)—>初始化前(postconstruct)—>初始化(initializingBean)—>初始化后(aop)—>代理对象—>Bean

1. 构造方法创建对象 利用该类的构造方法来实例化得到一个对象(但是如何一个类中有多个构造方法,Spring则会进行选择,这个叫做推断构造方法)

2.依赖注入 得到一个对象后,Spring会判断该对象中是否存在被@Autowired注解了的属性,把这些属性找出来并由Spring进行赋值(依赖注入)

3.回调 依赖注入后,Spring会判断该对象是否实现了BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口,如果实现了,就表示当前对象必须实现该接口中所定义的setBeanName()、setBeanClassLoader()、setBeanFactory()方法,那Spring就会调用这些方法并传入相应的参数(Aware回调)

4.@PostConstruct Aware回调后,Spring会判断该对象中是否存在某个方法被@PostConstruct注解了,如果存在,Spring会调用当前对象的此方法(初始化前)

5.InitializingBean 紧接着,Spring会判断该对象是否实现了InitializingBean接口,如果实现了,就表示当前对象必须实现该接口中的afterPropertiesSet()方法,那Spring就会调用当前对象中的afterPropertiesSet()方法(初始化)

6.AOP 最后,Spring会判断当前对象需不需要进行AOP,如果不需要那么Bean就创建完了,如果需要进行AOP,则会进行动态代理并生成一个代理对象做为Bean(初始化后)

创建完成后,Bean对象会存储在一个Map集合里

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

二、spring生命周期的流程

示例详解:
在这里插入图片描述

步骤1、
豆子工厂(BeanFactory)从xml文件、java配置或注解配置中读取“各种豆子的生产方法说明(BeanDefinition)

步骤2、
这些豆子分为“特殊豆子(实现spring指定的某些接口)”和“普通豆子”, 豆子工厂先生产出这些特殊豆子
步骤3和4
特殊豆子调用特定接口(例如BeanFactoryPostProcessor接口),可以对豆子工厂(BeanFactory)进行修改,或添加一些新豆子生产方法(即注册新的BeanDefinition到BeanFactory中)
步骤5
豆子工厂(BeanFactory)执行getBean方法生产其他的普通裸豆子。(调用类的构造方法,或FactoryBean的getObject方法,以及@Bean注解的方法)
步骤6
设置豆子的依赖关系以及属性值。
步骤7
调用豆子的@PostConstruct指定的方法
步骤8
调用豆子的InitializingBean接口方法
步骤9
调用豆子的initMethod指定的方法。

总结上述过程, 我们可以得到以下执行顺序 :
BeanFactoryPostProcessor ---> 普通Bean构造方法 ---> 设置依赖或属性 ---> @PostConstruct ---> InitializingBean ---> initMethod

三、BeanPostProcessor 与 BeanFactoryPostProcessor的区别

BeanFactoryPostProcessor:是针对于beanFactory的扩展点,即spring会在beanFactory初始化之后,beanDefinition都已经loaded,但是bean还未创建前进行调用,可以修改,增加beanDefinition
BeanPostProcessor:是针对bean的扩展点,即spring会在bean初始化前后 调用方法对bean进行处理

示例:
1.实体类

public class MyUser implements InitializingBean {
    private String name;
    private String desc;
 
    public MyUser() {
        System.out.println("2.无参构造,创建对象");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        System.out.println("3.调用setName()方法");
        this.name = name;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        System.out.println("4.调用setDesc()方法");
        this.desc = desc;
    }
    @Override
    public String toString() {
        return "MyUser{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("6.调用afterPropertiesSet() 初始化对象");
        this.name="韦小宝";
        this.desc="老子不干了";
    }
    //创建对象时指定initMethod
    public void initMethod(){
        System.out.println("7.调用initMethod()方法");
    }
}

2.BeanFactoryPostProcessor实现类

@Component
public class MyUserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("1.调用 BeanFactoryPostProcessor 的 postProcessBeanFactory(),执行时机:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行");
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myUser");
        MutablePropertyValues pv =  beanDefinition.getPropertyValues();
        if (pv.contains("desc")) {
            pv.addPropertyValue("desc", "在BeanFactoryPostProcessor中修改之后的备忘信息");
        }
    }
}

3.BeanPostProcessor实现类

@Component
public class MyUserBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("myUser")) {
            System.out.println("5.BeanPostProcessor,对象:" + beanName + ",在调用初始化(afterPropertiesSet)之前的数据:" + bean.toString());
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("myUser")) {
            System.out.println("8.BeanPostProcessor,对象:" + beanName + ",在调用初始化(initMethod)之后的数据:" + bean.toString());
        }
        return bean;
    }
}

4.配置类

@Configuration
@ComponentScan(value = "com.attuling.postprocessor")
public class PostProcessorConfig {

    @Bean(initMethod = "initMethod")
    public MyUser myUser(){
        MyUser myUser = new MyUser();
        myUser.setName("至尊宝");
        myUser.setDesc("他好像一条狗");
        return myUser;
    }
}

5.启动类

public class PostProcessorTest {
    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PostProcessorConfig.class);

        System.out.println("实例化、初始化bean完成");
        MyUser myUser = (MyUser)context.getBean("myUser");
        System.out.println("Name:"+myUser.getName());
        System.out.println("Desc:"+myUser.getDesc());
    }
}

输出结果:

1.调用 BeanFactoryPostProcessor 的 postProcessBeanFactory(),执行时机:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行
2.无参构造,创建对象
3.调用setName()方法
4.调用setDesc()方法
5.BeanPostProcessor,对象:myUser,在调用初始化之前的数据:MyUser{name=‘至尊宝’, desc=‘他好像一条狗’}
6.调用afterPropertiesSet() 初始化对象
7.调用initMethod()方法
8.BeanPostProcessor,对象:myUser,在调用初始化之后的数据:MyUser{name=‘韦小宝’, desc=‘老子不干了’}
实例化、初始化bean完成
Name:韦小宝
Desc:老子不干了

结论:
BeanFactoryPostProcessor实现类是在加载完beanDefinition,但还未调用构造创建对象的时候执行postProcessBeanFactory()
BeanPostProcessor实现类是在Bean实例化之后、初始化(包括afterPropertiesSet和initMethod)前后分别执行postProcessBeforeInitialization和postProcessAfterInitialization

BeanPostProcessor执行时机
在这里插入图片描述

四、BeanFactory与FactoryBean的区别

BeanFactory

BeanFactory创建对象的核心是:工厂、反射
在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。 ​
我们通过getBean()方法,传入参数——bean的名称或者类型,便可以从Spring容器中来获取bean。 ​
BeanFactory是用于访问Spring容器的根接口,是从Spring容器中获取Bean对象的基础接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范。
​ BeanFactory只是个接口,并不是IOC容器的具体实现,Spring容器给出了很多种 BeanFactory的 扩展实现,如:DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等

FactoryBean

Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口,然后在getObject()方法中灵活配置,来定制实例化Bean的逻辑
上面提到,我们可以通过BeanPostPorcessor来干涉Spring创建Bean的过程,但是如果我们想一个Bean完完全全由我们来创造,也是可以的,比如通过FactoryBean。但是通过这种方式创造出来的UserService的Bean,只会经过初始化后,其他Spring的生命周期步骤是不会经过的,比如依赖注入

五、Spring事务

当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。

Spring事务的代理对象执行某个方法时的步骤:

  1. 判断当前执行的方法是否存在@Transactional注解
  2. 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
  3. 修改数据库连接的autocommit为false
  4. 执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
  5. 执行完了之后如果没有出现异常,则提交,否则回滚

六、spring中的扩展点

1.自定义拦截器
实现HandlerInterceptor 接口 重写 preHandle 目标方法执行前执行 postHandle 目标方法执行后执行 afterCompletion 请求完成时执行
2.获取spring容器对象
实现BeanFactoryAware接口 ApplicationContextAware接口 ApplicationListener接口
3.全局异常处理
@RestControllerAdvice
4.类型转换器
spring目前支持3中类型转换器: Converter<S,T>:将 S 类型对象转为 T 类型对象 ConverterFactory<S, R>:将 S 类型对象转为 R 类型及子类对象
GenericConverter:它支持多个source和目标类型的转化,同时还提供了source和目标类型的上下文,这个上下文能让你实现基于属性上的注解或信息来进行类型转换
5.导入配置
@Import 注解

6.项目启动时
CommandLineRunner ApplicationRunner
7.修改BeanDefinition
实现BeanFactoryPostProcessor接口,重写postProcessBeanFactory 方法
8.初始化Bean前后
实现BeanPostProcessor接口,重写 postProcessBeforeInitialization 该在初始化方法之前调用。 postProcessAfterInitialization 该方法再初始化方法之后调用。
9.初始化
@PostConstruct
实现InitializingBean接口
10.关闭容器前
DisposableBean接口,并且重写它的destroy方法
11.自定义作用于
实现Scope接口

七、spring中的bean是线程安全的吗?

作用域。Spring中的Bean可以分为单例(singleton)和原型(prototype)两种作用域。对于原型(prototype)作用域的Bean,每次获取都会创建一个新的实例,因此这些Bean不是线程安全的。而单例(singleton)作用域的Bean在所有线程中共享同一个实例,如果有状态(即保存了数据),则可能存在线程安全问题。
状态。如果Bean是无状态的,那么它通常是线程安全的,因为无状态的Bean不会保存任何数据,不会影响多线程环境下的数据一致性。
因此,不能一概而论地说Spring的Bean是线程安全的,需要具体分析Bean的作用域是否具有状态

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神雕大侠mu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值