所有文章

https://www.cnblogs.com/lay2017/p/11478237.html

正文

在前面的几篇文章中,我们多次提到这么一个转化过程:

Bean配置 --> BeanDefinition --> Bean对象

Bean的配置可以是xml配置,也可以是java配置。BeanDefinition配置在内存中数据对象,也是Bean的元数据。在springboot启动过程当中,refresh上下文这个步骤将会解析xml配置以及java配置,从而把Bean的配置解析成为BeanDefinition。我们也可以将这个过程简称为Bean的元数据生成。

这里我们需要注意!refresh只是把BeanDefinition注册到BeanFactory中,而不是把Bean注册到BeanFactory中。(这里我们不讨论non-lazy-init=true的情况)

而是在我们调用上下文的getBean的时候才会去根据BeanDefinition生成

@Override
public Object getBean(String name) throws BeansException {
//
return getBeanFactory().getBean(name);
}

上下文的getBean方法把功能实现委托给了BeanFactory,跟进AbstractBeanFactory的getBean方法

@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

doGetBean获取Bean的逻辑

跟进doGetBean方法

protected <T> T doGetBean(
final String name,
@Nullable final Class<T> requiredType,
@Nullable final Object[] args,
boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name);
Object bean; // 如果拿到已经注册的单例Bean,直接返回结果
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else { // try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // // 创建单例
if (mbd.isSingleton()) {
// 回调创建
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
//
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
// 每次创建
prototypeInstance = createBean(beanName, mbd, args);
} finally {
//
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
//
}
} catch (BeansException ex) {
//
}
}
// return (T) bean;
}

该方法的逻辑是先去单例的缓存中找,如果找得到直接返回。如果找不到,那么判断是单例还是原型,如果是单例创建并缓存,如果是原型那么每次都创建新的。

getSingleton获取单例

跟进创建单例的时候的getSingleton方法

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 内置锁控制
synchronized (this.singletonObjects) {
// 双重校验
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// boolean newSingleton = false;
//
try {
// 回调创建Bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
//
}
catch (BeanCreationException ex) {
//
} finally {
//
}
if (newSingleton) {
// 添加单例到缓存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}

这里采用双重校验机制控制了单例,如果二次校验的时候发现缓存中没有Bean,那么就会回调创建的方法去创建一个Bean,然后再注册到本地堆缓存当中。

createBean创建Bean

我们先回到调用getSingleton的方法位置,看一下回调方法实什么

if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
//
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

创建实现委托给了createBean方法,该方法的实现属于AbstractAutowireCapableBeanFactory,跟进该类的CreateBean方法

@Override
protected Object createBean(
String beanName,
RootBeanDefinition mbd,
@Nullable Object[] args) throws BeanCreationException {
//
RootBeanDefinition mbdToUse = mbd; // try {
// 创建Bean实例
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
//
return beanInstance;
} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
//
} catch (Throwable ex) {
//
}
}

继续跟进doCreateBean

protected Object doCreateBean(
final String beanName,
final RootBeanDefinition mbd,
final @Nullable Object[] args) throws BeanCreationException { // 创建Bean实例对象
BeanWrapper instanceWrapper = null;
//
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//
try {
// 自动注入
populateBean(beanName, mbd, instanceWrapper);
//
} catch (Throwable ex) {
//
}
// return exposedObject;
}

该方法主要包含两个步骤,创建Bean的实例对象和自动注入

createBeanInstance创建实例

跟进createBeanInstance

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 省略 // 默认使用无参数构造方法获取实例
return instantiateBean(beanName, mbd);
}

跟进instantiateBean方法

private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
// 实例化
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
} else {
// 实例化
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
} catch (Throwable ex) {
//
}
} // 获取实例化策略
protected InstantiationStrategy getInstantiationStrategy() {
return this.instantiationStrategy;
}

默认的实例化策略是CglibSubclassingInstantiationStrategy,它又继承自SimpleInstantiationStrategy,跟进SimpleInstantiationStrategy类的instantiate方法

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 如果不存在需要被重写的方法,那么就不需要使用cglib重写并覆盖该类
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
//
}
// 通过构造方法实例化
return BeanUtils.instantiateClass(constructorToUse);
} else {
// 需要通过cglib生成
return instantiateWithMethodInjection(bd, beanName, owner);
}
}

到这里,BeanDefinition就被初步创建成为了一个Bean实例对象。

populateBean自动注入

前面我们说到,doCreateBean有两个步骤

1)创建Bean实例对象

2)自动注入

回顾一下doCreateBean的代码

protected Object doCreateBean(
final String beanName,
final RootBeanDefinition mbd,
final @Nullable Object[] args) throws BeanCreationException { // 创建Bean实例对象
BeanWrapper instanceWrapper = null;
//
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//
try {
// 自动注入
populateBean(beanName, mbd, instanceWrapper);
//
} catch (Throwable ex) {
//
}
// return exposedObject;
}

接下来,我们跟进populateBean方法看看当前这个创建好的Bean实例实怎么注入其它Bean的

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// // 获取待注入的property,配置文件中配置的<property>将在这里被处理
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); // 按照名字或者类型获取属性,这里会进行递归
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 按照名字获取属性
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 按照类型获取属性
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
} boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 后置处理器处理@Autowired @Resource等注解
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 注入<property>属性
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}

我们看到populateBean主要做两件事,获取属性值,然后把属性值给注入到Bean里面去。我们重点关注后置处理器处理@Autowired @Resource注解的逻辑。

AutowiredAnnotationBeanPostProcessor处理@Autowired注入注解

跟进AutowiredAnnotationBeanPostProcessor类的postProcessPropertyValues方法

public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) { return postProcessProperties(pvs, bean, beanName);
}

跟进postProcessProperties方法

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 获取当前Bean的元数据,将包含@Autowired等注解的标注的待注入元素
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 注入元素
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}

后置处理属性值包含两件事,找到当前Bean被@Autowired等注解标注的待注入的元素,然后注入相应的到元素。

跟进findAutowiringMetadata方法

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
// 构造元数据
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}

继续跟进buildAutowiringMetadata

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz; do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 找到注解@Autowired
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
//
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
}); // elements.addAll(0, currElements);
// 往父类递归
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements);
}

这里找到注解@Autowired的Field以后包装成Element,然后向父类递归,最后包装成元数据

我们回到postProcessProperties方法以后,再跟进inject注入方法看看

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable { if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
// 反射设置值,这里的取值会对依赖进行递归处理
field.set(target, getResourceToInject(target, requestingBeanName));
} else {
// 省略
}
}

这里主要是对Bean的Field的一个反射来设置值,值的获取将会进行递归处理

CommonAnnotationBeanPostProcessor处理@Resource注入注解

触发后置处理器的逻辑跟AutowiredAnnotationBeanPostProcessor是一样的,我们直接来看看CommonAnnotationBeanPostProcessor的buildAutowiringMetadata方法

private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz; do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
//
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
//
}
// 如果注解了@Resource
else if (field.isAnnotationPresent(Resource.class)) {
//
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
// 添加element
currElements.add(new ResourceElement(field, field, null));
}
}
}); // elements.addAll(0, currElements);
// 向父类递归
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements);
}

元数据返回以后的流程和@Autowired也是一样的。

总结

本文粗略地过了一下ioc依赖注入的过程,从BeanDefinition --> Bean的过程。我们一开始创建了Bean的实例,然后再通过递归解析依赖注入处理把Bean之间的关系结合处理。在最后还提了一下@Autowired和@Resource的后置处理器。

依赖注入的过程相对来说还是很复杂的,包含了非常多的细节处理。但是我们可以简单地去概括一下它,整个依赖注入的过程就是创建Bean,并建立Bean之间的关系。

springboot启动流程(九)ioc依赖注入的更多相关文章

  1. SpringBoot启动流程分析(六):IoC容器依赖注入

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  2. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  3. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  4. SpringBoot启动流程分析(一):SpringApplication类初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  5. SpringBoot启动流程分析(二):SpringApplication的run方法

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  6. SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  7. SpringBoot启动流程及其原理

    Spring Boot.Spring MVC 和 Spring 有什么区别? 分别描述各自的特征: Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等:但他们的 ...

  8. SpringBoot启动流程解析

    写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...

  9. SpringBoot 启动流程

    SpringBoot 启动流程 加载 resources/META-INF/spring.factories 中配置的 ApplicationContextInitializer 和 Applicat ...

随机推荐

  1. Qt编写自定义控件48-面板窗体控件

    一.前言 很多时候需要有一个控件,能够替代容器控件,自动容纳多个widget,自适应宽高,然后提供滚动条功能,这就必然需要用到QScrollArea控件,可设置各个子面板的间距等,也在很多系统中用到, ...

  2. List根据多个字段分组

    List<ClassEntity> distinctClass = classEntities.stream().collect(Collectors.collectingAndThen( ...

  3. confluent kafka connect remote debugging

    1. Deep inside of kafka-connect start up To begin with, let's take a look at how kafka connect start ...

  4. PAT 甲级 1041 Be Unique (20 分)(简单,一遍过)

    1041 Be Unique (20 分)   Being unique is so important to people on Mars that even their lottery is de ...

  5. Select 优化

    https://yq.aliyun.com/articles/704238?spm=a2c4e.11155472.0.0.66be4efeaUB5bk

  6. InfluxDB权限认证机制

    一.介绍 权限认证机制,顾名思义,就是对 InfluxDB 数据库添加权限访问控制,在默认情况下,InfluxDB 的权限认证机制是关闭的,也就是说所有用户都有所有权限. 老规矩,直接实践上手,下图是 ...

  7. CYLTabBarController的简单使用

    #pragma mark- 登录成功跳转至主页 -(void)jumpToMainVC { [UIApplication sharedApplication].statusBarStyle = UIS ...

  8. 为什么每次登录要手动 source /etc/profile ...

    由于执行顺序如下,故追个查看以下文件,看看是不是 JAVA_HOME, PATH 等环境变量在后面的文件中被重写覆盖了. 1. /etc/profile2. /etc/environment3. ~/ ...

  9. eclipse 解决POM文件错误:org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project.MavenProject, org.apache.maven.archiver.MavenArchiveConfiguration)

    解决方案: 更新eclipse中的maven插件 1.1 Help -> Install New Software -> Add 1.2 Location中输入 http://repo1. ...

  10. laravel进程管理supervisor的简单说明

    原文地址:https://www.cnblogs.com/zhoujinyi/p/6073705.html 背景: 项目中遇到有些脚本需要通过后台进程运行,保证不被异常中断,之前都是通过nohup.& ...