zoukankan      html  css  js  c++  java
  • spring 循环引用问题,在一次问题调试过程中发现有个小伙伴竟然把循环引用设置成false了。估计是百度的时候没小心额外的代码吧。。。

    循环引用属性操作:

    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相互引用的问题的答案也就渐渐浮出水面;如下图:

  • 相关阅读:
    E4A易安卓3.6无需注册编译Release
    PHP中几种常用的网页跳转代码
    超详细教你重新封装GHO(ndeer和绿茶)教程
    程序员和编码员之间的区别
    迅闪三层下载游戏无速度
    POST注册DZ论坛或发帖
    解决局域网文件共享设置
    妻子 情人 红颜知己
    照片与同行元素居中的方法
    【转】SVN使用教程总结
  • 原文地址:https://www.cnblogs.com/zzq-include/p/11979048.html
Copyright © 2011-2022 走看看