学习 Spring 之加载 bean

继上次注册 bean 之后好久没更新,这两天有空查了查资料也自己看了看 spring BeanFactory 的 getBean(beanName); 这个方法。因时间有限不能像之前那样复制代码并一行一行写上注释,这次只是将代码流程中的一些方法复制出来进行注释。

Spring 的版本是 5.1.3.RELEASE

首先是 getBean(String beanName);

Person person = (Person) context.getBean("person");

1.public Object getBean(String name);
1.1.doGetBean(name, null, null, false);
1.1.1.final String beanName = transformedBeanName(name); 先获取到对应的 beanName
1.1.2.Object sharedInstance = getSingleton(beanName); 在缓存中检查是否已经存在创建好的 bean 里面涉及到几个 map
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); Key: beanName value: bean 实例
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); Key: beanName value: bean 实例 与 singletonObjects 区别是用于存放 ObjectFactory.getObject(); 返回的 bean 实例
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); Key: beanName value: ObjectFactory 缓存的是单例工厂
1.1.3.if (isPrototypeCurrentlyInCreation(beanName)); 如果当前的 bean 正在创建则直接抛出异常 throw new BeanCurrentlyInCreationException(beanName);
1.1.4.BeanFactory parentBeanFactory = getParentBeanFactory(); 获取当前 bean 定义是否存在父容器 parentBeanFactory 比如 spring springmvc 父子容器
1.1.5.markBeanAsCreated(beanName); 标记当前 bean 正在创建打上标识
private final Set alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); 存储的是已经创建过的 beanName
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256); Key: beanName value: beanDefinition 存储是是已经创建过的 beanName 和 bean 定义
1.1.6.final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 获取到 beanName 对应的 beanDefinition 从 mergedBeanDefinitions 获取,第一次是返回一个新的 RootBeanDefinition
1.1.7.checkMergedBeanDefinition(mbd, beanName, args); 检查如果该 bean 是一个抽象类抛出异常 throw new BeanIsAbstractException(beanName);
1.1.8.String[] dependsOn = mbd.getDependsOn(); 获取是否需要处理依赖 bean 如果需要则遍历 dependsOn 的元素调用 getBean(dep);
1.1.9.if (mbd.isSingleton()) 如果该 bean 是单例的话直接创建
1.2.0.getSingleton(String beanName, ObjectFactory<?> singletonFactory); 调用 getSingleton 方法创建 bean,主要核心在第二个参数的 createBean(beanName, mbd, args); 方法

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory);

2.public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory);
2.1.Object singletonObject = this.singletonObjects.get(beanName); 尝试从缓存中获取如果获取不到并且该 bean 在销毁中则抛出异常 throw new BeanCreationNotAllowedException(beanName, message);
private boolean singletonsCurrentlyInDestruction = false; 销毁标识
2.2.beforeSingletonCreation(beanName); 将该 bean 加入创建单例 bean 的缓存中
2.3.singletonObject = singletonFactory.getObject(); 重点来了直接调用 ObjectFactory.createBean(beanName, mbd, args); 方法创建 bean
2.4.addSingleton(beanName, singletonObject); 最后将创建好的 bean 依次放入缓存
private final Set registeredSingletons = new LinkedHashSet<>(256); 存储的是创建好的 beanName

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args);

3.1.Class<?> resolvedClass = resolveBeanClass(mbd, beanName); 获取该 bean 对应的 class
3.2.mbdToUse.prepareMethodOverrides(); 设置该 bean 是否有重写方法
3.3.Object bean = resolveBeforeInstantiation(beanName, mbdToUse); 在该 bean 实例化之前,检查是否需要返回 proxy 代理对象。
3.4.Object beanInstance = doCreateBean(beanName, mbdToUse, args); 进行实例化 bean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args);

4.1.instanceWrapper = createBeanInstance(beanName, mbd, args); 创建 bean 里面就是调用反射使用构造器创建实例 bean
4.2.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); 获取所有的 BeanPostProcessor 判断里面元素是不是 MergedBeanDefinitionPostProcessor,再调用 MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
4.3.populateBean(beanName, mbd, instanceWrapper); 到了初始化 bean 数据的函数
4.4.initializeBean(beanName, exposedObject, mbd); 执行一些 bean 后置处理(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware、BeanPostProcessor);
4.5.registerDisposableBeanIfNecessary(beanName, bean, mbd); 注册销毁 bean 的回调

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw);

5.1.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) 到这步的时候 bean 实例化完成但是还没开始属性设值,取所有 InstantiationAwareBeanPostProcessor 的实现类调用 postProcessAfterInstantiation(bw.getWrappedInstance(), beanName); InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改
5.2.PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); 取出该 bean 的所有属性
5.3.autowireByName(beanName, mbd, bw, newPvs); 通过 name 找到所有属性值
5.4.autowireByType(beanName, mbd, bw, newPvs); 通过 type 找到所有属性值
5.5.for (BeanPostProcessor bp : getBeanPostProcessors()) 获取所有的 BeanPostProcessor
5.6.if (bp instanceof InstantiationAwareBeanPostProcessor) 找到所有的 InstantiationAwareBeanPostProcessor 类型
5.7.pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); 对采用 @Autowired 注解的依赖进行设值 field.set(bean, value);
5.8.if (pvs != null) applyPropertyValues(beanName, mbd, bw, pvs); 设置该 bean 的属性值

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd);

6.1.invokeAwareMethods(beanName, bean); 如果该 bean 实现了 Aware(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware) 接口则调用对应的 set 方法进行赋值
6.2.wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 获取出所有的 BeanPostProcessor 调用对应的 Object current = processor.postProcessBeforeInitialization(result, beanName);
6.3.invokeInitMethods(beanName, wrappedBean, mbd); 如果该 bean 实现了 InitializingBean 接口则调用对应的 ((InitializingBean) bean).afterPropertiesSet();
6.4.invokeCustomInitMethod(beanName, bean, mbd); 调用 bean 自定义的 init-method 方法
6.5.wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 获取出所有的 BeanPostProcessor 调用对应的 Object current = processor.postProcessAfterInitialization(result, beanName);

执行完这 6 步之后一个 spring bean 的加载就已经结束了进行逐层返回。帮助了自己巩固记忆,如果写的不足之处望指出谢谢各位观看!

注释

id 和 name

每个 bean 在配置的时候都有唯一的名字和多个别名,获取 bean 的时候可以通过 beanName 也可以通过别名

beanFactory.getBean("beanName or alias");

以下配置的结果就是:beanName 为 person,别名有 3 个,分别为 p1、p2、p3。

<bean id="person" name="p1, p2, p3" class="com.feil.springtest.ioc.test01.Person">

以下配置的结果就是:beanName 为 p1,别名有 2 个,分别为 p2、p3。

<bean name="p1, p2, p3" class="com.javadoop.example.MessageServiceImpl" />

以下配置的结果就是:beanName 为:com.feil.springtest.ioc.test01.Person#0,

扫描二维码关注公众号,回复: 6568029 查看本文章
<bean class="com.feil.springtest.ioc.test01.Person" />

以下配置的结果就是:beanName 为 person,没有别名。

<bean id="person" class="com.feil.springtest.ioc.test01.Person" />
profile

我们可以把不同环境的配置分别配置到单独的文件中

<beans profile="dev" ....>
	<bean ... />
	<bean ... />
	<bean ... />
</beans>
<beans profile="test" ....>
	<bean ... />
	<bean ... />
	<bean ... />
</beans>

当然,我们也可以在一个配置文件中使用:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <beans profile="dev">
        ...
    </beans>

    <beans profile="test">
        ...
    </beans>
</beans>

那么 spring 是怎么识别出不同的环境呢?Spring 在启动的过程中,会去寻找 “spring.profiles.active” 的属性值,根据这个属性值来的。那怎么配置这个值呢?
Spring 会在这几个地方寻找 spring.profiles.active 的属性值:操作系统环境变量、JVM 系统变量、web.xml 中定义的参数、JNDI。
最简单的方式肯定是在程序启动的时候指定:

-Dspring.spring.profiles.active="dev"
BeanPostProcessor

BeanPostProcessor接口作用:
如果我们想在 Spring 容器中完成 bean 实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个 BeanPostProcessor 接口实现类,然后注册到 Spring IoC 容器中。
BeanPostProcessor 概念在 Spring 中也是比较重要的。我们看下接口定义:

public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

1:后置处理器的 postProcessorBeforeInitailization 方法是 bean 在初始化之前会执行 postProcessBeforeInitialization 这个方法。
2:后置处理器的 postProcessorAfterInitailization 方法是在 bean 初始化完成之后会执行 postProcessAfterInitialization 这个方法。
请看第一个方法,这个方法接受的第一个参数是 bean 实例重点在返回值将会作为新的 bean 实例,那意味着什么呢?我们很容易想到的就是,我们这里可以对一些我们想要修饰的 bean 实例做一些事情。但是对于 Spring 框架来说,它会决定是不是要在这个方法中返回 bean 实例的代理。

猜你喜欢

转载自blog.csdn.net/qq_16830879/article/details/89921794