当前位置: 首页 > news >正文

西安市建设干部学校网站企业官网建站

西安市建设干部学校网站,企业官网建站,该怎么做网站编辑主要做什么,wordpress多媒体图片4.Spring【Java面试第三季】前言推荐4.Spring27_Aop的题目说明要求Spring的AOP顺序AOP常用注解面试题28_spring4下的aop测试案例业务类新建一个切面类MyAspect并为切面类新增两个注解:spring4springboot1.5.9pom测试类29_spring4下的aop测试结果aop正常顺序异常顺序…

4.Spring【Java面试第三季】

  • 前言
  • 推荐
  • 4.Spring
  • 27_Aop的题目说明要求
    • Spring的AOP顺序
      • AOP常用注解
      • 面试题
  • 28_spring4下的aop测试案例
      • 业务类
      • 新建一个切面类MyAspect并为切面类新增两个注解:
      • spring4+springboot1.5.9
        • pom
        • 测试类
  • 29_spring4下的aop测试结果
        • aop正常顺序+异常顺序
  • 30_spring5下的aop测试
      • spring5+springboot2.3.3
        • pom
        • 测试类
        • aop正常顺序+异常顺序
      • 结论
  • 31_spring循环依赖题目说明
    • Spring的循环依赖
      • 恶心的大厂面试题
      • 什么是循环依赖
      • 两种注入方式对循环依赖的影响
  • 32_spring循环依赖纯java代码验证案例
      • spring容器循环依赖报错演示BeanCurrentlylnCreationException
        • 循环依赖现象在Spring容器中注入依赖的对象,有2种情况
          • ==构造器方式注入依赖==
          • ==以set方式注入依赖==
  • 33_spring循环依赖bug演示
        • 重要code案例演示
          • code-java基础编码
          • spring容器
        • 重要结论(spring内部通过3级缓存来解决循环依赖)
  • 34_spring循环依赖debug前置知识
      • ==循环依赖Debug-困难,请坚持==
        • 实例化/初始化
        • 3个Map和四大方法,总体相关对象
        • A/B两对象在三级缓存中的迁移说明
  • spring循环依赖debug源码
  • 39_spring循环依赖小总结
      • ==总结spring是如何解决的循环依赖?==
        • 解释
        • Debug的步骤--->Spring解决循环依赖过程
  • 最后

前言

2023-2-3 13:51:54

以下内容源自
【尚硅谷Java大厂面试题第3季,跳槽必刷题目+必扫技术盲点(周阳主讲)-哔哩哔哩】
仅供学习交流使用

推荐

Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)

4.Spring

27_Aop的题目说明要求

Spring的AOP顺序

AOP常用注解

  • @Before 前置通知:目标方法之前执行
  • @After 后置通知:目标方法之后执行(始终执行)
  • @AfterReturning 返回后通知:执行方法结束前执行(异常不执行)
  • @AfterThrowing 异常通知:出现异常时候执行
  • @Around 环绕通知:环绕目标方法执行

面试题

  • 你肯定知道spring,那说说aop的全部通知顺序springboot或springboot2(spring4->spring5)对aop的执行顺序影响?

  • 说说你使用AOP中碰到的坑?

28_spring4下的aop测试案例

业务类

  • 接口CalcService
  • 接口实现类CalcServicelmpl新加@Service
  • 想在除法方法前后置入各种通知,引入切面编程

新建Maven工程,pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.9.RELEASE</version><relativePath/></parent><groupId>com.example</groupId><artifactId>spring4_aop</artifactId><version>0.0.1-SNAPSHOT</version><name>spring4_aop</name><description>spring4_aop</description><properties><java.version>8</java.version></properties><dependencies><!-- web  --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot AOP技术--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

启动类

package com.example.spring4_aop;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Spring4AopApplication {public static void main(String[] args) {SpringApplication.run(Spring4AopApplication.class, args);}}

接口CalcService

package com.example.spring4_aop.spring.aop;public interface CalcService {public int div(int x, int y);
}

接口实现类CalcServiceImpl新加@Service

package com.example.spring4_aop.spring.aop;import org.springframework.stereotype.Service;@Service
public class CalcServiceImpl implements CalcService {@Overridepublic int div(int x, int y) {int result = x / y;System.out.println("===>CalcServiceImpl被调用,计算结果为:" + result);return result;}
}

新建一个切面类MyAspect并为切面类新增两个注解:

  • @Aspect 指定一个类为切面类
  • @Component 纳入Spring容器管理
  • code
package com.example.spring4_aop.spring.aop;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class MyAspect {@Before("execution(public int com.example.spring4_aop.spring.aop.CalcServiceImpl.*(..))")public void beforeNotify() {System.out.println("********@Before我是前置通知");}@After("execution(public int com.example.spring4_aop.spring.aop.CalcServiceImpl.*(..))")public void afterNotify() {System.out.println("********@After我是后置通知");}@AfterReturning("execution(public int com.example.spring4_aop.spring.aop.CalcServiceImpl.*(..))")public void afterReturningNotify() {System.out.println("********@AfterReturning我是返回后通知");}@AfterThrowing(" execution(public int com.example.spring4_aop.spring.aop.CalcServiceImpl.*(..))")public void afterThrowingNotify() {System.out.println("********@AfterThrowing我是异常通知");}@Around(" execution(public int com.example.spring4_aop.spring.aop.CalcServiceImpl.*(..))")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {Object retvalue = null;System.out.println("我是环绕通知之前AAA");retvalue = proceedingJoinPoint.proceed();System.out.println("我是环绕通知之后BBB");return retvalue ;}
}

spring4+springboot1.5.9

pom

	 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.9.RELEASE</version><relativePath/></parent>

测试类

package com.example.spring4_aop;import javax.annotation.Resource;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.SpringVersion;
import org.springframework.test.context.junit4.SpringRunner;import com.example.spring4_aop.spring.aop.CalcService;@SpringBootTest
@RunWith(SpringRunner.class)
public class AopTest {@Resourceprivate CalcService calcService;@Testpublic void testAop4() {System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //SpringVersion.getVersion(), SpringBootVersion.getVersion()));calcService.div(10, 2);}
}

29_spring4下的aop测试结果

Spring Verision : 4.3.13.RELEASE, Sring Boot Version : 1.5.9.RELEASE.
我是环绕通知之前AAA
********@Before我是前置通知
===>CalcServiceImpl被调用,计算结果为:5
我是环绕通知之后BBB
********@After我是后置通知
********@AfterReturning我是返回后通知

修改测试类,让其抛出算术异常类:

package com.example.spring4_aop;import javax.annotation.Resource;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.SpringVersion;
import org.springframework.test.context.junit4.SpringRunner;import com.example.spring4_aop.spring.aop.CalcService;@SpringBootTest
@RunWith(SpringRunner.class)
public class AopTest {@Resourceprivate CalcService calcService;@Testpublic void testAop4() {System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //SpringVersion.getVersion(), SpringBootVersion.getVersion()));//        calcService.div(10, 2);calcService.div(10, 0);//将会抛出异常}
}

输出结果:

Spring Verision : 4.3.13.RELEASE, Sring Boot Version : 1.5.9.RELEASE.
我是环绕通知之前AAA
********@Before我是前置通知
********@After我是后置通知
********@AfterThrowing我是异常通知java.lang.ArithmeticException: / by zero

aop正常顺序+异常顺序

0350

  • 正常情况下:@Before前置通知----->@After后置通知----->@AfterRunning正常返回
  • 异常情况下:@Before前置通知----->@After后置通知----->@AfterThrowing方法异常

30_spring5下的aop测试

spring5+springboot2.3.3

pom

    <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId>
<!--        <version>1.5.9.RELEASE</version>--><version>2.3.3.RELEASE</version><relativePath/></parent>

测试类

package com.example.spring4_aop;import javax.annotation.Resource;import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.SpringVersion;
import org.springframework.test.context.junit4.SpringRunner;import com.example.spring4_aop.spring.aop.CalcService;@SpringBootTestpublic class AopTest {@Resourceprivate CalcService calcService;@Testpublic void testAop4() {System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //SpringVersion.getVersion(), SpringBootVersion.getVersion()));//        calcService.div(10, 2);calcService.div(10, 0);//将会抛出异常}@Testpublic void testAop5() {System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //SpringVersion.getVersion(), SpringBootVersion.getVersion()));calcService.div(10, 2);//        calcService.div(10, 0);//将会抛出异常}
}
Spring Verision : 5.2.8.RELEASE, Sring Boot Version : 2.3.3.RELEASE.
我是环绕通知之前AAA
********@Before我是前置通知
===>CalcServiceImpl被调用,计算结果为:5
********@AfterReturning我是返回后通知
********@After我是后置通知
我是环绕通知之后BBB

修改测试类,让其抛出算术异常类:

package com.example.spring4_aop;import javax.annotation.Resource;import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.SpringVersion;
import org.springframework.test.context.junit4.SpringRunner;import com.example.spring4_aop.spring.aop.CalcService;@SpringBootTestpublic class AopTest {@Resourceprivate CalcService calcService;@Testpublic void testAop4() {System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //SpringVersion.getVersion(), SpringBootVersion.getVersion()));//        calcService.div(10, 2);calcService.div(10, 0);//将会抛出异常}@Testpublic void testAop5() {System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //SpringVersion.getVersion(), SpringBootVersion.getVersion()));//        calcService.div(10, 2);calcService.div(10, 0);//将会抛出异常}
}

输出结果

Spring Verision : 5.2.8.RELEASE, Sring Boot Version : 2.3.3.RELEASE.
我是环绕通知之前AAA
********@Before我是前置通知
********@AfterThrowing我是异常通知
********@After我是后置通知java.lang.ArithmeticException: / by zero

aop正常顺序+异常顺序

同上结果

结论

0536

31_spring循环依赖题目说明

Spring的循环依赖

恶心的大厂面试题

  • 你解释下spring中的三级缓存?
  • 三级缓存分别是什么?三个Map有什么异同?
  • 什么是循环依赖?请你谈谈?看过spring源码吗?一般我们说spring容器是什么
  • 如何检测是否存在循环依赖?实际开发中见过循环依赖的异常吗?
  • 多例的情况下,循环依赖问题为什么无法解决?
  • 。。。

什么是循环依赖

  • 多个bean之间相互依赖,形成了一个闭环。比如:A依赖于B、B依赖于C、C依赖于A。

    • 代码
      0314
  • 通常来说,如果问Spring容器内部如何解决循环依赖,一定是指默认的单例Bean中,属性互相引用的场景。
    0407

两种注入方式对循环依赖的影响

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#spring-core
在这里插入图片描述

  • 循环依赖官网说明
    5838

  • 结论
    我们AB循环依赖问题只要A的注入方式是setter且singleton ,就不会有循环依赖问题。

32_spring循环依赖纯java代码验证案例

spring容器循环依赖报错演示BeanCurrentlylnCreationException

循环依赖现象在Spring容器中注入依赖的对象,有2种情况

构造器方式注入依赖

code

  • serviceA
@Component
public class ServiceA{private ServiceB serviceB;public ServiceA(ServiceB serviceB){this.serviceB = serviceB;}
}
  • serviceB
@Component
public class ServiceB{private ServiceA serviceA;public ServiceB(ServiceA serviceA){this.serviceA = serviceA;}
}
  • ClientConstructor
public class ClientConstructor{public static void main(String[] args){new ServiceA(new ServiceB(new ServiceA()));//这会抛出编译异常}
}

结论

  • 构造器循环依赖是无法解决的你想让构造器注入支持循环依赖,是不存在的
    在这里插入图片描述
以set方式注入依赖

code

  • ServiceAA
@Component
public class ServiceAA{private ServiceBB serviceBB;public void setServiceBB(ServiceBB serviceBB){this.serviceBB = serviceBB;System.out.println("A里面设置了B");}
}
  • ServiceBB
@Component
public class ServiceBB{private ServiceAA serviceAA;public void setServiceAA(ServiceAA serviceAA){this.serviceAA = serviceAA;System.out.println("B里面设置了A");}
}
  • ClientSet
public class ClientSet{public static void main(String[] args){//创建serviceAAServiceAA a = new ServiceAA();//创建serviceBBServiceBB b = new ServiceBB();//将serviceA入到serviceB中b.setServiceAA(a);//将serviceB法入到serviceA中a.setServiceBB(b);}
}

输出结果:

B里面设置了A
A里面设置了B

33_spring循环依赖bug演示

重要code案例演示

code-java基础编码
  • A
package com.example.spring4_aop.spring;public class A {private B b;public B getB() {return b;}public void setB(B b) {this.b = b;}public A() {System.out.println("---A created success");}
}
  • B
package com.example.spring4_aop.spring;public class B {private A a;public A getA() {return a;}public void setA(A a) {this.a = a;}public B() {System.out.println("---B created success");}
}
  • ClientCode
package com.example.spring4_aop.spring;public class ClientCode {public static void main(String[] args) {A a=new A();B b=new B();b.setA(a);a.setB(b);}
}

测试结果

---A created success
---B created success
spring容器
  • 默认的单例(singleton)的场景是支持循环依赖的,不报错
  • 原型(Prototype)的场景是不支持循环依赖的,会报错
  • 步骤
    • applicationContext.xml
    • 默认单例,修改为原型scope="prototype"ClientspringContainer
    • 循环依赖异常
      0508

applicationContext.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsd"><bean id="a" class="com.example.spring4_aop.spring.A"><property name="b" ref="b"></property></bean><bean id="b" class="com.example.spring4_aop.spring.B"><property name="a" ref="a"></property></bean></beans>

ClientSpringContainer

package com.example.spring4_aop.spring;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class ClientSpringContainer {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");A a = context.getBean("a", A.class);B b = context.getBean("b", B.class);}
}

输出结果

15:29:16.316 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@61064425
15:29:16.552 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [applicationContext.xml]
15:29:16.607 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'a'
---A created success
15:29:16.626 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'b'
---B created success

原型(Prototype)的场景是不支持循环依赖的,会报错

applicationContext.xml

    <bean id="a" class="com.example.spring4_aop.spring.A" scope="prototype"><property name="b" ref="b"></property></bean><bean id="b" class="com.example.spring4_aop.spring.B" scope="prototype"><property name="a" ref="a"></property></bean>

输出结果

15:33:03.481 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@61064425
15:33:03.669 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [applicationContext.xml]
---A created success
---B created success
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'b' while setting bean property 'b'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'a' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?Exception in thread "main" org.springframework.beans.factory.BeanCreationException:Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?

重要结论(spring内部通过3级缓存来解决循环依赖)

DefaultSingletonBeanRegistry

只有单例的bean会通过三级缓存提前暴露来解决循环依赖的问题,而非单例的bean,每次从容器中获取都是一个新的对象,都会重新创建,所以非单例的bean是没有缓存的,不会将其放到三级缓存中。

第一级缓存(也叫单例池)singletonObjects:存放已经经历了完整生命周期的Bean对象。

第二级缓存:earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完。)

第三级缓存:Map<String, ObjectFactory<?>> singletonFactories,存放可以生成Bean的工厂。

package org.springframework.beans.factory.support;...public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {.../** Cache of singleton objects: bean name to bean instance. */private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name to ObjectFactory. */private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name to bean instance. */private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);...}

34_spring循环依赖debug前置知识

循环依赖Debug-困难,请坚持

实例化/初始化

  • 实例化

    • 内存中申请一块内存空间
    • 租赁好房子,自己的家当还未搬来。
  • 初始化属性填充

    • 完成属性的各种赋值
    • 装修,家具,家电进场。

3个Map和四大方法,总体相关对象

0433

第一层singletonObjects存放的是已经初始化好了的Bean,

第二层earlySingletonObjects存放的是实例化了,但是未初始化的Bean,

第三层singletonFactories存放的是FactoryBean。假如A类实现了FactoryBean,那么依赖注入的时候不是A类,而是A类产生的Bean

package org.springframework.beans.factory.support;...public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {.../** 单例对象的缓存:bean名称—bean实例,即:所谓的单例池。表示已经经历了完整生命周期的Bean对象第一级缓存*/private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/**早期的单例对象的高速缓存: bean名称—bean实例。表示 Bean的生命周期还没走完(Bean的属性还未填充)就把这个 Bean存入该缓存中也就是实例化但未初始化的 bean放入该缓存里第二级缓存*/private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);/**单例工厂的高速缓存:bean名称—ObjectFactory表示存放生成 bean的工厂第三级缓存*/private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);...}

A/B两对象在三级缓存中的迁移说明

1.A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B。

2.B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A。

3.B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态),然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A自己放到一级缓存里面。

@FunctionalInterface
public interface ObjectFactory<T> {T getObject() throws BeansException;}

spring循环依赖debug源码

跳转
spring循环依赖debug源码

39_spring循环依赖小总结

总结spring是如何解决的循环依赖?

0327

解释

Spring创建 bean主要分为两个步骤,创建原始bean对象,接着去填充对象属性和初始化

每次创建 bean之前,我们都会从缓存中查下有没有该bean,因为是单例,只能有一个

当我们创建 beanA的原始对象后,并把它放到三级缓存中,接下来就该填充对象属性了,这时候发现依赖了beanB,接着就又去创建beanB,同样的流程,创建完beanB填充属性时又发现它依赖了beanA又是同样的流程,

不同的是:

这时候可以在三级缓存中查到刚放进去的原始对象beanA.所以不需要继续创建,用它注入 beanB,完成 beanB的创建

既然 beanB创建好了,所以 beanA就可以完成填充属性的步骤了,接着执行剩下的逻辑,闭环完成

0913

Spring解决循环依赖依靠的是Bean的"中间态"这个概念,而这个中间态指的是已经实例化但还没初始化的状态—>半成品
实例化的过程又是通过构造器创建的,如果A还没创建好出来怎么可能提前曝光,所以构造器的循环依赖无法解决。”对

Spring为了解决单例的循坏依赖问题,使用了三级缓存:
其中一级缓存为单例池(singletonObjects)。
二级缓存为提前曝光对象(earlySingletonObjects)。
三级级存为提前曝光对象工厂(singletonFactories) 。

假设A、B循环引用,实例化A的时候就将其放入三级缓存中,接着填充属性的时候,发现依赖了B,同样的流程也是实例化后放入三级缓存,接着去填充属性时又发现自己依赖A,这时候从缓存中查找到早期暴露的A,没有AOP代理的话,直接将A的原始对象注入B,完成B的初始化后,进行属性填充和初始化,这时候B完成后,就去完成剩下的A的步骤,如果有AOP代理,就进行AOP处理获取代理后的对象A,注入B,走剩下的流程。

Debug的步骤—>Spring解决循环依赖过程

请添加图片描述

  1. 调用doGetBean()方法,想要获取beanA,于是调用getSingleton()方法从缓存中查找beanA
  2. 在getSingleton()方法中,从一级缓存中查找,没有,返回null
  3. doGetBean()方法中获取到的beanA为null,于是走对应的处理逻辑,调用getSingleton()的重载方法(参数为ObjectFactory的)
  4. 在getSingleton()方法中,先将beanA_name添加到一个集合中,用于标记该bean正在创建中。然后回调匿名内部类的creatBean方法
  5. 进入AbstractAutowireCapableBeanFactory#ndoCreateBean,先反射调用构造器创建出beanA的实例,然后判断:是否为单例、是否允许提前暴露引用(对于单例一般为true)、是否正在创建中(即是否在第四步的集合中)。判断为true则将beanA添加到【三级缓存】中
  6. 对beanA进行属性填充,此时检测到beanA依赖于beanB,于是开始查找beanB
  7. 调用doGetBean()方法,和上面beanA的过程一样,到缓存中查找beanB,没有则创建,然后给beanB填充属性
  8. 此时 beanB依赖于beanA,调用getSingleton()获取beanA,依次从一级、二级、三级缓存中找,此时从三级缓存中获取到beanA的创建工厂,通过创建工厂获取到singletonObject,此时这个singletonObject指向的就是上面在doCreateBean()方法中实例化的beanA
  9. 这样beanB就获取到了beanA的依赖,于是beanB顺利完成实例化,并将beanA从三级缓存移动到二级缓存中
  10. 随后beanA继续他的属性填充工作,此时也获取到了beanB,beanA也随之完成了创建,回到getsingleton()方法中继续向下执行,将beanA从二级缓存移动到一级缓存中

最后

2023-2-3 21:23:12

这篇博客能写好的原因是:站在巨人的肩膀上

这篇博客要写好的目的是:做别人的肩膀

开源:为爱发电

学习:为我而行

http://www.ds6.com.cn/news/107232.html

相关文章:

  • 个人简历表下载可填写西安网站优化培训
  • 建设网站选什么地方的主机优化大师软件下载
  • 品牌线上推广方式广州排前三的seo公司
  • 专门做门的网站如何注册网站
  • 南京凯盛建设集团官方网站seop
  • 上海人才网招聘网最新招聘百度seo优化
  • 山西省网站建设价格房地产市场现状分析
  • 海南 网站 建设电销名单渠道在哪里找
  • 团购网站百度推广账户优化方案
  • 建设独立网站点击排名优化
  • 建筑工程网上叫什么网站页面怎么优化
  • 营销型网站建设总结网站seo基本流程
  • 怎样做编辑发到网站如何推广宣传一个品牌
  • 开发员给我用织梦做的网站网站检测
  • 网站设计用什么软件做的店铺推广软文500字
  • 企业做网站的注意什么怎样做平台推广
  • 有哪些网站可以做微商在线搭建网站
  • 免费舆情网站下载百度竞价排名模式
  • 网站开发美工苏州seo
  • 美妆网站模板海淀搜索引擎优化seo
  • 教育类网站如何做百度自然搜索排名优化
  • WordPress可以做网盘吗win10最强优化软件
  • 烟台网站制作设计西安seo网站关键词优化
  • 软件开发需要考什么专业证书国外seo
  • 百度短网址生成今日头条搜索优化
  • 建设银行网站如何查询开户行网络广告营销方案
  • 东莞市研发网站建设企业上海有实力的seo推广咨询
  • 怎样创办网站百度网站打不开
  • 重庆seo网站网站申请
  • 做网站推广怎么定位客户浏览器下载安装2023版本