Spring源码笔记

BeanDefinition

BeanDefinition表示Bean定义,Spring根据BeanDefinition来创建Bean对象,BeanDefinition有很多的属性用来描述Bean,BeanDefinition是Spring中非常核心的概念。

BeanFactory

BeanFactory是一种“Spring容器”,BeanFactory就是Bean工厂,顾名思义,它可以用来创建Bean,获取Bean,BeanFactory是Spring中非常核心的组件。

BeanDefinition、BeanFactory、Bean对象之间的关系

BeanFactory将利用BeanDefinition来生成Bean对象,BeanDefinition相当于BeanFactory的原材料,Bean对象就相当于BeanFactory所生产出来的产品。

BeanFactory的核心子接口

DefaultListableBeanFactory 功能

支持单例Bean、支持Bean别名、支持父子BeanFactory、支持Bean类型转化、支持Bean后置处理、支持FactoryBean、支持自动装配,等等

Bean生命周期

Bean生命周期描述的是Spring中一个Bean创建过程和销毁过程中所经历的步骤,其中Bean创建过程是重点。
我们开发者可以利用Bean生命周期机制对Bean进行自定义加工。

大致顺序:
---- BeanDefinition 进行Bean的定义
---- 构造方式推断 选出一个构造方法
---- 实例化 构造方法反射得到对象
---- 属性填充 给属性进行自动填充
---- 初始化 对其他属性复制、校验
---- 初始化后 AOP、生成代理对象

BeanDefinition
BeanDefinition表示Bean定义,它定义了某个Bean的类型,Spring就是利用BeanDefinition来创建Bean的,比如需要利用BeanDefinition中beanClass属性确定Bean的类型,从而实例化出来对象。

构造方式推断
一个Bean中可以有多个构造方法,此时就需要Spring来判断到底是用哪个构造方法,这个过程是比较复杂的(后续完善补充)。通过构造方法推断之后确定一个构造方法之后,就可以利用构造方法实例化得到一个对象了。

实例化
通过构造方法反射得到一个实例化对象,在Spring中,可以通过BeanPostProcessor机制对实例化进行干预。

属性填充
实例化所得到的对象,是“不完整”的对象,“不完整”的意思是该对象中的某些属性还没有进行属性填充,也就是Spring还没有自动给某些属性赋值,属性填充就是我们通常说的自动注入,依赖注入。

初始化
在一个对象的属性填充之后,Spring提供了初始化机制,我们开发者可以利用初始化机制对Bean进行自定义加工,比如可以利用InitializingBean接口来对Bean中的其他属性进行赋值,或者对Bean中的某些属性进行校验。

初始化后
初始化后是Bean创建生命周期中的最后一个步骤,我们常说的AOP机制,就是在这个步骤中通过BeanPostProcessor机制实现的,初始化之后得到的对象才是真正的Bean对象。

@Autowired是什么

@Autowired表示某个属性是否需要进行依赖注入,可以卸载属性和方法上。注解中的required属性值默认为true,表示如果没有对象可以注入给属性则抛出异常。

@Autowired加在某个属性上,Spring在进行Bean的生命周期过程中,在属性填充这一步,会基于实例化出来的对象,对该对象中加了@Aotuwired的属性自动给属性赋值。

Spring会先根据属性的类型去Spring容器中找出该类型所有的Bean对象,如果找出来多个,则再根据属性的名字从多个中确定一个。如果required值为true,并且根据属性信息找不到对象,则抛出异常。

当@Autowired注解写在某个方法上时,Spring在Bean生命周期的属性填充阶段,会根据方法的参数类型、参数名字从Spring容器找到对象当做方法入参,自动反射调用该方法。

@Autowired加在构造方法上时,Spring会在推断构造方法阶段,选择该构造方法来进行实例化,在反射调用构造方法之前,会先根据构造方法参数类型,参数名从Spring容器中找到Bean对象,当做构造方法入参。

@Resource是什么

@Resource注解与@Autowired类似,也是用来进行依赖注入的,@Resource是Java层面所提供的注解,@Autowired是Spring所提供的注解,他们依赖注入的底层实现也逻辑不同。

@Resource注解中有一个name属性,针对name属性是否有值,@Resource的依赖注入底层流程是不同的。

@Resource如果name属性有值,那么Spring会直接根据所制定的name值去Spring容器中找Bean对象,如果找到了则成功,没有找到,则报错。

如果@Resource中的name属性没有值,则:
1.先判断该属性名字在Spring容器中是否存在对象。
2.如果存在,则成功找到Bean对象进行注入。
3.如果不存在,则根据属性类型去Spring容器找Bean对象,找到一个则进行注入。

@Value是什么

@Value注解和@Resource、@Autowired类似,也是用来对属性进行依赖注入的,只不过@Value是用来从Properties文件中来获取值的,并且@Value可以解析SpEL(Spring表达式)。

@Value(“yck”)
直接将字符串“yck”赋值给属性,如果属性类型不是String,或无法进行类型转化,则报错。
@Value(“$ {yck}”)
将会把${}中的字符串当做key,从Properties文件中找出对应的value赋值给属性
@Value(“#{yck}”)
会将#{}中的字符串当做Spring表达式进行解析,Spring会把"yck"当做beanName,并从Spring容器中找对一个bean,如果找到则进行属性注入,没找到则报错。

FactoryBean是什么

FactoryBean是Spring所提供的一种较灵活的创建Bean的方式,可以通过实现FactoryBean接口中的getObject()方法来返回一个对象,这个对象就是最终的Bean对象。

FactoryBean接口中的方法
Object getObject(): 返回的是Bean对象
boolean isSingleton(): 返回的是否是单例Bean对象
Class getObjectType(): 返回的是Bean对象的类型

FactoryBean对象本身也是一个Bean,同时它相当于一个小型工厂,可以生产出另外的Bean。
BeanFactory是一个Spring容器,是一个大型工厂,它可以生产出各种各样的Bean。

FactoryBean机制被广泛的应用在Spring内部和Spring与第三方框架或组件的整合过程中。

ApplicationContext是什么

ApplicationContext是比BeanFactory更加强大的Spring容器,它既可以创建bean、获取bean,还支持国际化、事件传播、获取资源等BeanFactory不具备的功能。

解析

先看以下代码

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/beanFactory.xml");

ClassPathXmlApplicationContext对象,调用ClassPathXmlApplicationContext的构造方法。

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[]{configLocation}, true, (ApplicationContext)null);
}

ClassPathXmlApplicationContext是一个XML应用上下文,从类路径获取上下文定义文件,再调用本类的另一个构造方法,传入的refresh参数值为true,表示要调用AbstractApplicationContext的refresh()方法自动刷新上下文。

AbstractApplicationContext
---- refresh()
refresh()方法是用来加载所有的Bean定义和创建所有的单例。
(1)startupShutdownMonitor是启动关闭监控标识,是用来同步应用上下文(context)刷新(refresh)和销毁(destroy)操作。
(2)调用本类的prepareRefresh()方法做刷新上下文的准备。
(3)告诉子类刷新内部bean工厂,准备在上下文使用的Bean工厂。
(4)允许在上下文子类中对bean工厂进行后处理。
(5)调用在上下文中注册为bean的工厂处理器。
(6)注册bean处理器用来拦截bean的创建。
(7)为此上下文初始化消息源。
(8)为此上下文初始化事件多播器。
(9)在特定上下文子类中初始化其他特殊bean。
(10)检查监听器bean并注册它们。
(11)实例化所有剩余的(非延迟初始化)单例。
(12)最后一步:发布相应的事件。
(13)如果以上过程出现异常,就销毁已创建的单例以避免资源悬空。将active标识设置为false,将异常向上抛出。
(14)无论是否出现异常,最后重置Spring核心中的常见自省缓存,因为我们可能不再需要单例bean的元数据。

代码如下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        this.prepareRefresh();
        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();
        }
 
    }
}

AbstractApplicationContext
---- prepareRefresh()
(1)startupDate是用来记录上下文启动的系统时间。
(2)将上下文是否关闭的标识设置为false。将上下文是否活跃的标识设置为true。(3)this.initPropertySources()用来初始化上下文环境的所有占位符属性源。(4)this.getEnvironment().validateRequiredProperties()会初始化environment属性,验证所有标记为必需的属性都是可解析的。
(5)earlyApplicationListeners是刷新之前就会注册的本地监听器Set集合,applicationListeners是静态指定的监听器Set集合,当earlyApplicationListeners为空时,会初始化内容是applicationListeners;当earlyApplicationListeners不为空时,会将applicationListeners清空,内容再重置为earlyApplicationListeners。
(6)最后再初始化earlyApplicationEvents属性,earlyApplicationEvents是在多播器设置之前发布的应用程序事件。

如下:

protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);
    if (this.logger.isDebugEnabled()) {
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Refreshing " + this);
        } else {
            this.logger.debug("Refreshing " + this.getDisplayName());
        }
    }
 
    this.initPropertySources();
    this.getEnvironment().validateRequiredProperties();
    if (this.earlyApplicationListeners == null) {
        this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
    } else {
        this.applicationListeners.clear();
        this.applicationListeners.addAll(this.earlyApplicationListeners);
    }
 
    this.earlyApplicationEvents = new LinkedHashSet();
}

TODO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值