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

4.Spring【Java面试第三季】

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

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

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

开源:为爱发电

学习:为我而行

相关文章:

4.Spring【Java面试第三季】

4.Spring【Java面试第三季】前言推荐4.Spring27_Aop的题目说明要求Spring的AOP顺序AOP常用注解面试题28_spring4下的aop测试案例业务类新建一个切面类MyAspect并为切面类新增两个注解&#xff1a;spring4springboot1.5.9pom测试类29_spring4下的aop测试结果aop正常顺序异常顺序…...

ZLibrary使用说明-Zlirbrary

ZLibrary使用说明如果您是一位书虫&#xff0c;那么ZLibrary是一个值得一试的网站。该网站提供了大量的免费电子书籍&#xff0c;涵盖了各种不同的主题和类别。下面是一些有关如何使用ZLibrary的详细说明&#xff1a;第1步&#xff1a;访问ZLibrary网站要使用ZLibrary&#xff…...

TwinCAT3第三方伺服电机——汇川SV660N使用

目录 一、第三方伺服在TC3中配置和使用 二、xml文件拷贝 ​编辑 三、IO中扫描伺服 四、工程测试 五、汇川伺服参数设置说明 一、第三方伺服在TC3中配置和使用 在倍福控制系统中使用第三方伺服可以参见本人另一篇博客&#xff0c;有详细教程说明。本文仅仅对SV660N伺服设置…...

进制转换(二进制,八进制,十进制,十六进制)涵盖整数与小数部分,内容的图片全为手写【详细图解】

各种进制之间的相互转换1. 各进制表示数1.1 数码1.2 基数1.3 位权2. 十进制转换为其他进制2.1 整数部分2.2 小数部分3. 其他进制转换为十进制4. 二进制转换为八进制5. 二进制转换为十六进制6. 八进制转换为十六进制1. 各进制表示数 二进制&#xff1a;0&#xff0c;1逢二进一 八…...

谈谈XR关键技术及VR/AR/MR/XR关系

一、先别被VR/AR/MR/XR搞晕&#xff0c;说说区别虚拟现实&#xff08;Virtual Reality&#xff0c;VR&#xff09;、增强现实&#xff08;Augmented Reality&#xff0c;AR&#xff09;等业务以其三维化、自然交互、空间计算等完全不同于当前移动互联网的特性&#xff0c;被认为…...

acwing1562 微博转发(宽搜)

微博被称为中文版的 Twitter。 微博上的用户既可能有很多关注者&#xff0c;也可能关注很多其他用户。 因此&#xff0c;形成了一种基于这些关注关系的社交网络。 当用户在微博上发布帖子时&#xff0c;他/她的所有关注者都可以查看并转发他/她的帖子&#xff0c;然后这些人…...

如何使用Arsenal快速部署功能强大的Bug Bounty工具

关于Arsenal Arsenal是一个功能强大且使用简单的Shell脚本&#xff08;Bash&#xff09;&#xff0c;该工具专为漏洞赏金猎人设计&#xff0c;在该工具的帮助下&#xff0c;我们可以轻松在自己环境中安装并部署目前社区中功能最为强大的网络侦查工具、漏洞扫描工具和其他安全研…...

(十)python网络爬虫(理论+实战)——正则表达式再讨论、常用正则表达式整理

系列文章目录 (1)python网络爬虫—快速入门(理论+实战)(一) (2)python网络爬虫—快速入门(理论+实战)(二) (3) python网络爬虫—快速入门(理论+实战)(三) (4)python网络爬虫—快速入门(理论+实战)(四) (5)...

MyBatis-Plus特性及插件整合

了解MyBatis-Plus 什么是MyBatis-Plus&#xff1f; mybatisPlus在mybatis的基础上继续针对CRUD操作进行优化&#xff0c;在原有的基础上提供了公共的接口BaseMapper&#xff0c;我们在创建接口Mapper时只需要继承这个接口即可调用MyBatisPlus已经提供好的方法&#xff0c;sql…...

应用篇|网络安全知识培训考试,答题小程序操作指引

网络安全知识培训考试&#xff0c;答题小程序操作指引关于全民防诈反诈宣传或者网络安全知识学习&#xff0c;如何进行组织一场微信线上答题考试&#xff1f;可以在小程序“护网专题信息安全知识竞答”&#xff0c;先创建一个学习单位/小组&#xff0c;再邀请成员加入单位/小组…...

官方不推荐@Autowired

1用lombok注解 2 构造器...

【牛客刷题专栏】0x0E:JZ6 从尾到头打印链表(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录前言问题…...

Zeppelin安装

1、下载Zeppelin 下载地址&#xff1a;Download 2.解压 [rootguo147 install]# tar -zxvf zeppelin-0.10.0-bin-all.tgz -C ../soft/ //修改文件名 [rootguo147 soft]# mv zeppelin-0.10.0-bin-all/ zeppelin 3.配置 //进入conf 目录 [rootguo147 conf]# pwd /opt/soft/zepp…...

【蓝桥杯选拔赛真题38】python目标值判断 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析

目录 python目标值判断 一、题目要求 1、编程实现 2、输入输出 二、解题思路...

Python jieba分词如何添加自定义词和去除不需要长尾词

Python jieba分词如何添加自定义词和去除不需要长尾词 作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 通过如下代码&#xff0c;读取一个txt的高频词汇&#xff1a; # 找到高频词汇t…...

云打包苹果证书生成、上架和应用截屏攻略

在使用apicloud或hbuilderx这些跨端的开发工具开发移动应用的时候&#xff0c;假如是打包ios应用&#xff0c;是需要生成苹果证书、证书profile文件&#xff0c;和对应用上架的。首先要普及一个概念&#xff0c;苹果的应用是无法像安卓那样挂在自己的服务器上下载直接安装就可以…...

洛谷 U91193:棋盘覆盖问题 ← 分治法

【题目来源】https://www.luogu.com.cn/problem/U91193【问题描述】 在一个2^k * 2^k&#xff08;k≥0&#xff09;个方格组成的棋盘中&#xff0c;恰有一个方格与其他方格不同&#xff0c;称该方格为一特殊方格。现在用4种不同形状的 L型&#xff08;占3小格&#xff09;骨牌覆…...

基于OMAPL138+FPGA核心板多核软件开发组件MCSDK开发入门(下)

本文测试板卡为创龙科技 SOM-TL138F 是一款基于 TI OMAP-L138(定点/浮点 DSP C674x + ARM9)+ 紫光同创 Logos/Xilinx Spartan-6 低功耗 FPGA 处理器设计的工业级核心板。核心板内部OMAP-L138 与 Logos/Spartan-6 通过 uPP、EMIFA、I2C 通信总线连接,并通过工业级 B2B连接器引…...

熵,线性规划,半监督自监督聚类打标签

1.熵 信息熵是消除不确定性所需信息量的度量。 信息熵就是信息的不确定程度&#xff0c;信息熵越小&#xff0c;信息越确定。 对象的信息熵是正比于它的概率的负对数的&#xff0c;也就是 I©−log(pc) 其中n为事件的所有可能性。 为什么使用交叉熵&#xff1f;在机器学习…...

求极限方法总结

1.利用四则运算法则求极限 2.利用两个重要极限求极限 //0除以0型 //1的无穷次方型 3.利用等价无穷小替换替换求极限 //在等价替换时注意和差项 4.利用洛必达法则求极限 5.利用夹逼准则求极限 6.利用单调有界数列极限准则求极限 7.利用无穷小的性质求极限 8.利用函数的连续性…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...

《Docker》架构

文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器&#xff0c;docker&#xff0c;镜像&#xff0c;k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...

WEB3全栈开发——面试专业技能点P7前端与链上集成

一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染&#xff08;SSR&#xff09;与静态网站生成&#xff08;SSG&#xff09; 框架&#xff0c;由 Vercel 开发。它简化了构建生产级 React 应用的过程&#xff0c;并内置了很多特性&#xff1a; ✅ 文件系…...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...

土建施工员考试:建筑施工技术重点知识有哪些?

《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目&#xff0c;核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容&#xff0c;附学习方向和应试技巧&#xff1a; 一、施工组织与进度管理 核心目标&#xff1a; 规…...

Qt的学习(一)

1.什么是Qt Qt特指用来进行桌面应用开发&#xff08;电脑上写的程序&#xff09;涉及到的一套技术Qt无法开发网页前端&#xff0c;也不能开发移动应用。 客户端开发的重要任务&#xff1a;编写和用户交互的界面。一般来说和用户交互的界面&#xff0c;有两种典型风格&…...