循环引用属性操作:

1)AbstractAutowireCapableBeanFactory类中的allowCircularReferences被设置为了false。

2)代码:

AnnotationConfigApplicationContext a = new AnnotationConfigApplicationContext("");

a.setAllowCircularReferences();

spring初始化过程

1 初始化spring上下文,new DefaultListBeanFactory()

2 之后调用refresh()

3 refresh()中包含了springBean初始化的全部过程

4 完成spring扫描所有的Bean,在invokeBeanFactoryPostProcessors()

5 其中最核心的初始化方法是finishBeanFactoryInitialization(传入beanFactory)

6 之后继续调用preInstantiateSingletons,进入初始化的准备。

7 核心方法继续调用getBean,因为getBean才会真正的初始化Bean。那么在getBean中会调用两次getSingleton方法,“第一次调用是解决Bean相互引用问题,第二个参数默认传递为true”。

8 首次调用getSingleton基本会返回null因为这个时候 bean没有被创建成功,所以在singleobjectsMap中还没有办法找到创建成功的Bean,这个时候继续会判断当前Bean的是否处于创建状态,如果是的话从earlySingletonObjectsMap中获取一定获取的到;如果不在创建状态,那么这个时候首次调用返回null。
***在这里说明下,bean在最开始仅仅是个“创建中”的状态,也就是单独创建了对象,但是依赖注入还没有做,这样的对象会放入earlySingletonObjectsMap中!

9 二次调用getSingleton方法,初始化bean的时候还会检查singleobjectsMap集合,如果仍然获取不到则去执行createBean方法创建对象,委托模式调用了doCreateBean方法的createInstance方法创建了wapper对象。

9.1 其实在这里创建的包装对象还仅仅是一个java对象,还没有进行属性的注入因为注入要通过populateBean方法处理。

ps:spring的BeanFactory后置处理器共有8个。

10 注入方法是通过 populateBean 方法开始执行的,遇到@Autowired属性则通过BeanFactory的后置处理器找到相应的BeanDefine再次调用getBean方法执行第6步骤即可。

10.1 populateBean 方法执行时首先判断当前类需不需要注入;

10.2 调用doCreateBean之后在调用initializeBean方法,该方法中使用“策略模式”对Bean的继承接口进行扩展;

10.3 initializeBean方法中的invokeAwareMethods方法会回调Bean实现了以下接口的方法:BeanNameAware,BeanClassLoaderAware,BeanFactoryAware

private void invokeAwareMethods(String beanName, Object bean) {
if(bean instanceof Aware) {
if(bean instanceof BeanNameAware) {
((BeanNameAware)bean).setBeanName(beanName);
} if(bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware)bean).setBeanClassLoader(this.getBeanClassLoader());
} if(bean instanceof BeanFactoryAware) {
((BeanFactoryAware)bean).setBeanFactory(this);
}
} }

10.4 往下跟踪applyBeanPostProcessorsBeforeInitialization方法中继续使用Bean的后置处理器,回调对应接口的方法:

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
Iterator var4 = this.getBeanPostProcessors().iterator(); do {
if(!var4.hasNext()) {
return result;
} BeanPostProcessor beanProcessor = (BeanPostProcessor)var4.next();
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
} while(result != null); return result;
} @Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null; if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
} if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
invokeAwareInterfaces(bean);
} return bean;
}

ps:之前提到过两次getSingleton方法是为了处理Bean相互引用的问题的答案也就渐渐浮出水面;如下图:

spring 循环引用问题,在一次问题调试过程中发现有个小伙伴竟然把循环引用设置成false了。估计是百度的时候没小心额外的代码吧。。。的更多相关文章

  1. Spring源码浅析之bean实例的创建过程(二)

    在上一篇内容中,介绍了doGetBean方法的源码内容,知道了bean在创建的过程中,有三个范围,单例.多例.Scope,里面都使用到了createBean.下面本篇文章的主要内容,就是围绕creat ...

  2. 【Spring Framework】Spring IOC详解及Bean生命周期详细过程

    Spring IOC 首先,在此之前,我们就必须先知道什么是ioc,ioc叫做控制反转,也可以称为依赖注入(DI),实际上依赖注入是ioc的另一种说法, 1.谁控制谁?: 在以前,对象的创建和销毁都是 ...

  3. ThreadLocalMap的enrty的key为什么要设置成弱引用

    ThreadLocalMap的Enrty代码实现: 将Entry的Key设置成弱引用,在配合线程池使用的情况下可能会有内存泄露的风险.之设计成弱引用的目的是为了更好地对ThreadLocal进行回收, ...

  4. 【spring mvc】springmvc在tomcat中的执行过程

    一.WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象(每个web应用程序唯一),它代表当前web应用web容器提供其一个全局的上下文环境,其为后面的spri ...

  5. js:for循环ul/li,获取当前被点击元素的id,以及给其他li设置属性

    js:for循环ul/li,获取当前被点击元素的id,以及给其他li设置属性 <!doctype html> <html> <head> <meta char ...

  6. 【Java面试宝典】说说你对 Spring 的理解,非单例注入的原理?它的生命周期?循环注入的原理, aop 的实现原理,说说 aop 中的几个术语,它们是怎么相互工作的?

    AOP与IOC的概念(即spring的核心) IOC:Spring是开源框架,使用框架可以使我们减少工作量,提高工作效率并且它是分层结构,即相对应的层处理对应的业务逻辑,减少代码的耦合度.而sprin ...

  7. Spring源码浅析之bean实例的创建过程(一)

    在之前的文章内容中,简单介绍了bean定义的加载过程,下面这篇的主要内容就是bean实例的创建过程. bean实例的创建方式 ApplicationContext context = new Clas ...

  8. 用fluent模拟内循环床气化燃烧(调试过程记录)

    模拟对象为文献Combined gasification of coal and biomass in internal circulating fluidized bed[1]中的内循环气化炉.[1]h ...

  9. Spring 源码学习 - 单例bean的实例化过程

    本文作者:geek,一个聪明好学的同事 1. 简介 开发中我们常用@Commpont,@Service,@Resource等注解或者配置xml去声明一个类,使其成为spring容器中的bean,以下我 ...

随机推荐

  1. Jenkins拉取github库代码执行构建

    前言 上篇文章写了关于定时构建,以及构建后发送邮件的内容,但是构建时运行的代码是我们手动添加到Jenkins工作空间的.这篇文章我们说一说自动从GitHub远程库拉取代码,执行构建,废话不多说,开始! ...

  2. go 学习 (五):包管理

    一.设置环境变量 二.启用 go modules 功能 并设置代理 https://goproxy.io/zh/ 补充: GO111MODULE  有三个值:on.off.auto GO111MODU ...

  3. MySQL 内连接、外连接、左连接、右连接、全连接……太多了

    用两个表(a_table.b_table),关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接.外连接( 左(外)连接.右(外)连接.全(外)连接). 主题:内连接 ...

  4. 【loj2983】【WC2019】数树

    题目 两颗\(n\)个点的树T1和T2,有\(y\)种颜色; 现在给每个点染色,要求公共边端点的颜色相同,求: ​ 1.op=0 , T1和T2都确定,求合法染色方案数: ​ 2.op=1 , T1确 ...

  5. git dev分支合并线上master

    1.本地dev新建/切换本地master 新建 git checkout -b master 切换 git checkout  master 2.本地dev与本地master合并 git merge ...

  6. QML学习(三)——<QML命名规范>

    QML对象声明 QML对象特性一般使用下面的顺序进行构造: id 属性声明 信号声明 JavaScript函数 对象属性 子对象 状态 状态切换 为了获取更好的可读性,建议在不同部分之间添加一个空行. ...

  7. 帝国cms万能标签实现标题截取后自动加入省略号的方法

    很多采用帝国CMS建站的站长都会遇到标题过长导致页面排版错乱的情况,这时候往往需要用标题截取并追加上省略号的方法予以解决.对此,帝国CMS万能标签标题截取后自动加入省略号,没有达到字数的则不加省略号可 ...

  8. 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数

    今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...

  9. [源码分析]LinkedHashMap

    一个键有序的 HashMap   可以将 LinkedHashMap 理解为 LinkList + HashMap,所以研究LinkedHashMap之前要先看HashMap代码.这里不再赘述.其实L ...

  10. egg.js搭建 api设置跨域

    1.egg简述 Egg.js,为企业级框架和应用而生,是阿里开源的企业级 Node.js 框架. 2.特点 Egg 奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开 ...