• spring的bean创建流程源码解析



    本文基于 Spring 5.0.2.RELEASE

    spring 是 Java Web 开发中,非常常用的框架。它的基础作用是为我们生成对象。这里涉及到 2 个概念。IOC 和 DI。

    IOC 和 DI

    IOC:Inversion of Control,控制反转。强调的是原来在程序中创建Bean的权利反转给第三方,这里的第三方,其实就是 spring 框架。

    DI:依赖注入。比如 UserService类,依赖 UserDao,但是 UserDao 是由 BeanFactory 注入给 UserService 的。

    BeanFactory

    1、BeanFactory是Spring的早期接口,称为Spring的Bean工厂.它提供了一系列的方法,用于获取 Bean
    在这里插入图片描述
    BeanFactory 的默认实现类是 DefaultListableBeanFactory,DefaultListableBeanFactory主要是管理 BeanDefinition 对象,并根据BeanDefinition 对象创建 Bean 对象。
    在这里插入图片描述
    在DefaultListableBeanFactory中,实现了BeanDefinitionRegistry接口,这个接口定义了关于 BeanDefinition 的注册、移除、查询等一系列的操作。

    DefaultListableBeanFactory还继承了DefaultSingletonBeanRegistry,这个类中,实现了三级缓存,创建单例 Bean 的操作。????BeanDefinition对象,怎么传给DefaultSingletonBeanRegistry对象的????

    DefaultListableBeanFactory总结起来,就是可以增删改查BeanDefinition定义对象,并通过父类方法,生成 Bean 对象。但是它并没有把 xml 文件,或者注解,解析成BeanDefinition对象的功能。这个功能是在ApplicationContext实现的。

    ApplicationContext

    实现的接口

    1、BeanFactory接口

    ApplicationContext 继承了很多接口,每增加一个接口,都增加了对应的功能。
    在这里插入图片描述
    但是,ApplicationContext 中,并不是继承了 DefaultListableBeanFactory,而是实现了 BeanFactory接口,并引入了 DefaultListableBeanFactory 作为属性,由 DefaultListableBeanFactory 实现 BeanFactory 相关的功能。(组合优于继承)

    在这里插入图片描述

    注意看,AnnotationConfigApplicationContext中包含 beanFactory 属性,在它的父类 AbstractApplicationContext中,实现了 getBean 等 方法,都是调用 beanFactory 来实现的。

    @Override
    public Object getBean(String name) throws BeansException {
      assertBeanFactoryActive();
      return getBeanFactory().getBean(name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ApplicationContext 相比 BeanFactory,还多继承了四个接口,功能如下:

    2、MessageSource 国际化接口
    public static void main(String[] args) {
      ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
      System.out.println(context.getMessage("hi", null, Locale.CHINA));
      System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在 resources 目录下创建三个配置文件,注意设置 idea 的 properties 编码格式是 utf-8
    messages.properties 空内容
    messages_en.properties 填写内容 hi=hello
    messages_zh.properties 填写内容 hi=你好

    运行代码,控制台打印如下,说明国际化生效

    你好
    hello
    
    • 1
    • 2
    3、ResourcePatternResolver,资源解析接口

    可以用于读取配置文件

    public static void main(String[] args) throws IOException {
      ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
      //读取类类路径下文件
      Resource[] resources1 = context.getResources("classpath:application.properties");
      //读取jar 包中的类路径文件,注意带个 * 号
      Resource[] resources2 = context.getResources("classpath*:META-INF/spring.factories");
      //读取文件目录下的文件
      Resource[] resources3 = context.getResources("file:/tmp/test.log");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    4、EnvironmentCapable接口,用于获取环境变量,配置信息
      public static void main(String[] args) throws IOException {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        //读取application.properties 中的内容
        System.out.println(context.getEnvironment().getProperty("server.port"));
        //读取系统环境变量
        System.out.println(context.getEnvironment().getProperty("JAVA_HOME"));
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    5、ApplicationEventPublisher 事件发布接口
    // 自定义事件
    public class UserLoginEvent extends ApplicationEvent {
      public UserLoginEvent(Object source) {
        super(source);
      }
    }
    //发布事件
      public static void main(String[] args) throws IOException {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
        context.publishEvent(new UserLoginEvent("username"));
      }
    //接收事件
    @Component
    public class UserMessageService {
    
      @EventListener
      public void sendMessage(UserLoginEvent event){
        Object source = event.getSource();
        System.out.println("欢迎用户:"+source);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    当调用publishEvent发布事件时,会调用到 sendMessage 方法。(观察者模式)

    总结:
    1、BeanFactory 类,用于生成 Bean。
    2、ApplicationContext,继承了 BeanFactory 接口,引入了 DefaultListableBeanFactory对象,体现了组合优于继承的原则。
    3、ApplicationContext,实现了其他接口,增加了国际化,事件发布,资源解析,读取配置等功能。

    Application 的继承体系

    在这里插入图片描述

    常用的 ApplicationContext 有 3 个,分别是
    AnnotationConfigApplicationContext,用于加载注解配置类的ApplicationContext
    FileSystemXmlApplicationContext,用于加载磁盘路径下的xml配置的ApplicationContext
    ClassPathXmlApplicationContext,用于加载类路径下的xml配置的ApplicationContext
    如果 spring 中加入了 Web 相关的组件,那么使用的 ApplicationContext 是
    XmlWebApplicationContext,用于web环境下,加载类路径下的xml配置的ApplicationContext
    AnnotationConfigWebApplicationContext,用于web环境下,加载磁盘路径下的xml配置的ApplicationContext

    Bean 的创建执行流程

    以解析 xml 文件为例,使用ClassPathXmlApplicationContext,流程如下:

    1、加载xml配置文件,解析获取配置中的每个的信息,封装成一个个的BeanDefinition对象;
    2、将BeanDefinition存储在一个名为beanDefinitionMap的Map中;
    3、ApplicationContext底层遍历beanDefinitionMap,创建Bean实例对象;
    4、创建好的Bean实例对象,被存储到一个名为singletonObjects的Map中;
    5、当执行applicationContext.getBean(beanName)时,从singletonObjects去匹配Bean实例返回。

    在这里插入图片描述

    Spring 给开发者留下的扩展点

    主要有两个地方,
    1 是对 beanDefinitionMap 进行添加,修改,只要向 beanDefinitionMap 中添加了 BeanDefinition,就会被 Spring 生成 Bean。
    2 是当 Bean 创建完成后,可以对 Bean 对象进行修改,比如 AOP,注解,都是生成代理 Bean,替换原有的 Bean。

    流程如下:

    结合代码描述

    代码入口:

    ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application-single.xml");
    
    UserService userService = context.getBean("userServiceBeanId",UserService.class);
    
    System.out.println(userService.getName());
    
    • 1
    • 2
    • 3
    • 4
    • 5

    进入ClassPathXmlApplicationContext

    	public ClassPathXmlApplicationContext(
    			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
    			throws BeansException {
    
    		//1、返回一个classloader
    		//2、返回一个解析器
    		super(parent);  // ===> 1
    		// 1、获取环境(系统环境、jvm环境)
    		// 2、设置Placeholder占位符解析器,${xxx}.xml解析为完整文件名
    		// 2、将xml的路径解析完存储到数组
    		setConfigLocations(configLocations); //  ===>
    		//默认为true
    		if (refresh) {
    			//核心方法,入口
    			refresh();  // ===>  magic happens here!
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    进入 Refresh 方法

    	@Override
    	public void refresh() throws BeansException, IllegalStateException {
    		// synchronized块锁(monitorenter --monitorexit)
    		// 不然 refresh() 还没结束,又来个启动或销毁容器的操作
    		//	 startupShutdownMonitor就是个空对象,锁
    		synchronized (this.startupShutdownMonitor) {
    			//1、【准备刷新】,设置了几个变量,也是准备工作
    			prepareRefresh();   //  ===>
    			// 2、【获得新的bean工厂】关键步骤,重点!
    			//2.1、关闭旧的 BeanFactory
    			//2.2、创建新的 BeanFactory(DefaluListbaleBeanFactory)
    			//2.3、解析xml/加载 Bean 定义、注册 Bean定义到beanFactory(不初始化)
    			//2.4、返回全新的工厂
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    			//3、【bean工厂前置操作 】为BeanFactory配置容器特性
    			// 例如类加载器、表达式解析器、注册默认环境bean、后置管理器
    			prepareBeanFactory(beanFactory);// ===>
    			try {
    				// 4、【bean工厂后置操作】此处为空方法,如果子类需要,自己去实现
    				postProcessBeanFactory(beanFactory);  // ===> 空的!
    
    				//5、【调用bean工厂后置处理器】,开始调用我们自己实现的接口
    				//调用顺序一:先执行BeanDefinitionRegistryPostProcessor接口的方法,它也继承了BeanFactoryPostProcessor
    				//调用顺序二:后执行BeanFactoryPostProcessor接口的方法,用于修改 beanDefinition
    				invokeBeanFactoryPostProcessors(beanFactory);  // ===>  重头戏
    
    				//6、【注册bean后置处理器】只是注册,但是还不会调用
    				//逻辑:找出所有实现BeanPostProcessor接口的类,分类、排序、注册
    				registerBeanPostProcessors(beanFactory);  // ===>  关键点
    				// Initialize message source for this context.
    				//7、【初始化消息源】国际化问题i18n,参照https://nacos.io/
    				initMessageSource(); // ===> 就是往factory加了个single bean
    				// Initialize event multicaster for this context.
    				//8、【初始化事件广播器】初始化自定义的事件监听多路广播器
    				// 如果需要发布事件,就调它的multicastEvent方法
    				// 把事件广播给listeners,其实就是起一个线程来处理,把Event扔给listener处理
    				// (可以通过 SimpleApplicationEventMulticaster的代码来验证)
    				initApplicationEventMulticaster(); // ===> 同样,加了个bean
    				// 9、【刷新】这是个protected空方法,交给具体的子类来实现
    				//  可以在这里初始化一些特殊的 Bean
    				// (在初始化 singleton beans 之前)
    				onRefresh();  // ===> 空的!一般没人管它
    				//10、【注册监听器】,监听器需要实现 ApplicationListener 接口
    				// 也就是扫描这些实现了接口的类,给他放进广播器的列表中
    				// 其实就是个观察者模式,广播器接到事件的调用时,去循环listeners列表,
    				// 挨个调它们的onApplicationEvent方法,把event扔给它们。
    				registerListeners();  // ===> 观察者模式
    				//11、 【结束bean工厂初始化操作】
    				//1、初始化所有的 singleton beans,反射生成对象/填充
    				//2、 调用Bean的前置处理器和后置处理器
    				// 关键点:getBean方法里完成
    				finishBeanFactoryInitialization(beanFactory);  // ===>  关键点!
    				// 12、结束refresh操作
    				// 发布事件与清除上下文环境
    				finishRefresh();
    			} catch (BeansException ex) {
    
    			} finally {
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    Bean 的创建流程总结:

    在这里插入图片描述

    面试中说的三级缓存是什么?

    三级缓存是为了解决循环依赖,也是为了存储单例对象

    Spring提供了三级缓存存储 完整Bean实例 和 半成品Bean实例 ,用于解决循环引用问题

    在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:

    public class DefaultSingletonBeanRegistry ... { 
      //1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
      Map<String, Object> singletonObjects = new ConcurrentHashMap(256); 
      //2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存" 
      Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16); 
      //3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存" 
      Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    三级缓存怎么解决循环依赖问题?核心就是先把半成品的 Bean 放入一个缓存中

    假设 Bean1 和 Bean2 循环依赖,那么创建过程如下:
    1、Bean1 实例化对象,但尚未初始化,将 Bean1 存储到三级缓存;
    2、Bean1 属性注入,需要 Bean2,从缓存中获取,没有 Bean2;
    3、Bean2 实例化对象,但尚未初始化,将 Bean2 存储到到三级缓存;
    4、Bean2 属性注入,需要 Bean1,从三级缓存获取 Bean1,Bean1 从三级缓存移入二级缓存;
    5、Bean2 执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存;
    6、Bean1 注入 Bean2;
    7、Bean1 执行其他生命周期过程,最终成为一个完整 Bean,存储到一级缓存,删除二三级缓存。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例如下:

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(Config.class);
        context.refresh();
        context.close();
    }
    
    @Configuration
    static class Config {
        @Bean // 解析 @Aspect、产生代理
        public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
            return new AnnotationAwareAspectJAutoProxyCreator();
        }
    
        @Bean // 解析 @Autowired
        public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
            return new AutowiredAnnotationBeanPostProcessor();
        }
    
        @Bean // 解析 @PostConstruct
        public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
            return new CommonAnnotationBeanPostProcessor();
        }
    
        @Bean
        public Advisor advisor(MethodInterceptor advice) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut, advice);
        }
    
        @Bean
        public MethodInterceptor advice() {
            return (MethodInvocation invocation) -> {
                System.out.println("before...");
                return invocation.proceed();
            };
        }
    
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
    
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }
    
    static class Bean1 {
        public Bean1() {
            System.out.println("Bean1()");
        }
        @Autowired public void setBean2(Bean2 bean2) {
            System.out.println("Bean1 setBean2(bean2) class is: " + bean2.getClass());
        }
        @PostConstruct public void init() {
            System.out.println("Bean1 init()");
        }
    }
    
    static class Bean2 {
        public Bean2() {
            System.out.println("Bean2()");
        }
        @Autowired public void setBean1(Bean1 bean1) {
            System.out.println("Bean2 setBean1(bean1) class is: " + bean1.getClass());
        }
        @PostConstruct public void init() {
            System.out.println("Bean2 init()");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    执行 main 方法后,打印如下:

    Bean1()
    Bean2()
    Bean2 setBean1(bean1) class is: class com.spring.test.A17_1$Bean1
    Bean2 init()
    Bean1 setBean2(bean2) class is: class com.spring.test.A17_1$Bean2
    Bean1 init()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    为什么是三级缓存而不是二级缓存?

    如果只是为了解决循环依赖问题,那么二级缓存就够了。为什么要设计三级缓存?为了解决循环依赖时,某个 Bean 需要被 AOP 增强,生成代理对象。

    在Bean 的创建流程总结中,注意看图,Bean 的初始化方法执行完成后,才执行 BeanPostProcess的后处理方法,如果这个 Bean 被 AOP 增强了,会生成代理对象。

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean方法

    // 方法一:实例化! Bean的构造函数在这里被调用!
    instanceWrapper = createBeanInstance(beanName, mbd, args); 
    //方法二:注入相关的属性!【关键点】
    populateBean(beanName, mbd, instanceWrapper);
    //方法三:初始化方法,这里会调用 BeanPostProcess
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition) 方法

    //调用Bean的前置处理器!我们自己实现的bean的processer在这里!
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    
    // 1、调用初始化方法, 处理 bean 中定义的 init-method,
    //2、如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法
    invokeInitMethods(beanName, wrappedBean, mbd); 
    
    // 调用Bean的后置管理器!用于生成代理aop也在这里偷偷做了手脚……注意aop调试时,看这句后wrappedBean的变化!
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    通过上述源码,可以看到,代理对象 生成,是在初始化方法执行后,才生成代理对象。

    这个功能,在循环依赖场景下,就会存在问题。

    刚才的 Bean1 和 Bean2 循环依赖时,打印如下:

    1、Bean1()
    2、Bean2()
    3、Bean2 setBean1(bean1) class is: class com.spring.test.A17_1$Bean1
    4、Bean2 init()
    5、Bean1 setBean2(bean2) class is: class com.spring.test.A17_1$Bean2
    6、Bean1 init()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果是在初始化后,才对 Bean1 进行增强生成代理对象,那么是在第 6 步完成后,才生成代理对象。这样Bean2 setBean1(bean1) 注入的就是原始对象,不是代理对象。不符合预期。

    所以 Spring 打了一个补丁,提供一个三级缓存,三级缓存中存储的不是未完成的对象,而是 Bean 的创建工厂ObjectFactory。当需要Bean1 对象时,执行的是 ObjectFactory 的 getObject 方法,这个方法中,也会进行是否 AOP 的判断,如果是,就生成代理对象。

    源码如下:

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

    // () -> getEarlyBeanReference(beanName, mbd, bean) 是 ObjectFactory 匿名实现类 的简写
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    
    • 1
    • 2

    getEarlyBeanReference 方法

    	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    		Object exposedObject = bean;
    		//是否存在实现InstantiationAwareBeanPostProcessors接口的类
    		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    			//循环所有Bean后置处理器
    			for (BeanPostProcessor bp : getBeanPostProcessors()) {
    				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
    					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
    					//重点:开始创建AOP代理,
    					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
    				}
    			}
    		}
    		//总结
    		//1、如果不调用后置,返回的bean和三级缓存一样
    		//2、如果调用AOP后置,返回的就是代理对象
    		//3、这就是三级缓存设计的巧妙之处!!!!Map>
    		// 结论:虽然二级缓存能解决循环依赖,但是使用不了aop了,也就是扩展点没有了
    		return exposedObject;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    示例如下:修改 Bean1 代码增加一个 foo 方法,让 Bean1 被 AOP 增强

        static class Bean1 {
            public void foo() {
    
            }
            public Bean1() {
                System.out.println("Bean1()");
            }
            @Autowired public void setBean2(Bean2 bean2) {
                System.out.println("Bean1 setBean2(bean2) class is: " + bean2.getClass());
            }
            @PostConstruct public void init() {
                System.out.println("Bean1 init()");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    再次执行,观察打印效果:

    Bean1()
    Bean2()
    Bean2 setBean1(bean1) class is: class com.spring.test.A17_1$Bean1$$EnhancerBySpringCGLIB$$28831f11
    Bean2 init()
    Bean1 setBean2(bean2) class is: class com.spring.test.A17_1$Bean2
    Bean1 init()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意看,Bean1 对象,很早就变成了代理对象,说明是三级缓存生效了。注意:虽然很早就变成代理对象了,但是初始化方法还没执行。

    总结下:

    AOP 代理对象生成的时机?

    1、如果存在循环依赖,是在三级缓存中生成代理对象

    2、如果不存在循环依赖,是在 Bean 初始化方法执行后生成。

    为什么需要三级缓存?

    为了打补丁,让循环依赖的 AOP 的 Bean,能正常注入到其他 Bean 中。

    1,2,3 三级缓存的作用是什么?

    一级缓存存储已经完全创建好的单例对象

    二级缓存存储未完成的,还被其他 Bean 引用的对象

    三级缓存,用于存储未完成的对象工厂,且没被其他对象引用过。

  • 相关阅读:
    Promise与async/await与Generator
    路由器配置单区域(多区域)OSPF
    《算法竞赛·快冲300题》每日一题:“取石子游戏”
    小张的秋招面经(持续更新版)
    梳理一名Go后端程序员日常用的软件~
    在 Spring Boot 中使用 Jdbi3 简介
    软件工程第一次作业参考答案
    php二维数组查找某个id=1的元素
    leetcode 13. Roman to Integer(罗马字母转数字)
    Adaptive AUTOSAR 学习笔记 5 - 架构 - 物理视图
  • 原文地址:https://blog.csdn.net/zlx510tsde/article/details/138167918