当前位置: 首页 > 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.利用函数的连续性…...

Flutter Scrollable 中ViewPort滚动原理

关于Flutter Sliver组件内容可以参考下面这位博主博客&#xff0c;写的已经非常好了&#xff0c;这里就不再赘述。 38、Flutter之 可滚动组件简介_flutter 可滑动_风雨「83」的博客-CSDN博客 通过阅读上面的博客&#xff0c;我们已经知道了Scrollable和Viewport基础概念&#…...

多目标粒子群结合极限学习机ELM求解帕累托前沿,MOPSO-ELM

目录 背影 parte前沿的定义 注意事项 基于多目标粒子群结合极限学习机的帕累托前沿求解帕累托前沿 主要参数 MATLAB代码 效果图 结果分析 展望 背影 在目标优化过程种,很多时候都两个或者多个目标,并且目标函数不能同时达到最优,鱼与熊掌不可兼得,这个时候可以通过求解帕…...

(二十)操作系统-信号量机制

文章目录一、知识预览二、前篇文章知识点回顾三、信号量机制四、信号量机制—整形信号量五、信号量机制—记录型信号量六、总结一、知识预览 二、前篇文章知识点回顾 进程互斥的四种软件实现方式&#xff1a;单标志法、双标志先检查、双标志后检查、Peterson算法。&#xff08;…...

ceph osd slow ops 检测

目的 常用的方法检测 ceph slow 问题 参考 yceph -scluster:id: 22908555-e596-4c2d-a1f6-34fcf4d3e935health: HEALTH_WARNDegraded data redundancy: 46384/12805029 objects degraded (0.362%), 145 pgs degraded, 122 pgs undersized309 slow ops, oldest one blocked…...

百度CTO王海峰:深度学习平台+大模型,夯实产业智能化基座

2月27日&#xff0c;中国人工智能学会首届智能融合产业论坛在成都顺利举办。本届论坛由中国人工智能学会&#xff08;CAAI&#xff09;主办&#xff0c;中国人工智能学会智能融合专委会、百度公司、深度学习技术及应用国家工程研究中心和电子科技大学联合承办。中国工程院多名院…...

【C++】vector的基本使用

难道向上攀爬的那条路&#xff0c;不是比站在顶峰更让人热血沸腾吗&#xff1f; 文章目录一、vector和string的联系与不同二、vector的扩容操作1.resize() &#xff08;缺省值为匿名对象&#xff09;&& reserve()2.reserve在g和vs上的扩容机制3.reserve异地扩容和shri…...

社交媒体营销的5个好处

有些人认为&#xff0c;社交媒体营销不能直接与销售挂钩。这就是为什么在制定营销策略时&#xff0c;社交媒体营销会被部分人忽视的原因。然而&#xff0c;与其他广告渠道不同&#xff0c;社交媒体是双向渠道。忽视社交媒体营销将影响与客户的关系。最重要的是&#xff0c;它将…...

飞行机器人专栏(十)-- 异构多视角视觉系统

感知系统架构为满足天空端主控制器的诸如RGB-D图像处理等大容量数据吞吐、高速并行计算、实时运动控制以及通信和可视化任务的计算算力需求&#xff0c;同时优化功耗表现&#xff0c;采用了结构紧凑、功耗表现优异的边缘计算硬件NVIDA IJetson AGXOrin 。该开发者套件包含高性能…...

2023年湖北住建厅八大员各岗位题库精准小题库-启程别

2023年湖北住建厅八大员各岗位题库精准小题库-启程别 住建厅八大员&#xff08;施工员、质量员、资料员、材料员、机械员、标准员、劳务员&#xff09; 各岗位题库分2种&#xff1a; 1.住建厅八大员报名之后会有培训任务&#xff0c;完成培训任务学习才能安排考试&#xff0c;…...

志愿者招募令|来!一起Build OceanBase第一次开发者大会

2023 年 3 月 25 日&#xff0c;我们将开启第一次 OceanBase 开发者大会&#xff0c;走近开发者&#xff0c;共同探讨单机分布式、云原生、HTAP 等数据库前沿趋势&#xff0c;分享全新的产品 Roadmap&#xff0c;交流场景探索和最佳实践。 为了让活动现场更有活力&#xff0c;…...

北京建设高端网站的/精准ip地址查询工具

C TCP Server 用C写网络程序需要winsock2.h这个头文件,还有添加一个ws2_32.lib的lib库. VC2005添加Lib库的方法1 项目- Server属性- 配置属性- 连接器- 附加依赖项2 #pragma comment(lib,"ws2_32.lib")3 查找ws2_32.lib文件项目- 添加现有项,将ws2_32.lib作为文件…...

公司网站后台如何上传视频/太原seo网站管理

web应用常见的资源存方式在WEB-INF下新建lib&#xff0c;存放要使用的jar包在WEB-INF下新建jsp文件夹&#xff0c;存放jsp文件。首页除外&#xff0c;首页就放到web下。在web下&#xff0c;或WEB-INF下&#xff0c;新建css、js、image文件夹&#xff0c;存放相关文件。WEB-INF目…...

个人网站可以做企业宣传/域名注册哪个网站好

1.美国大学列表 https://university.graduateshotline.com/ubystate.html 2.获取浏览器 user agent 信息 https://www.whatismybrowser.com/detect/what-is-my-user-agent —————————————————————————————— 转载于:https://www.cnblogs.com/hebol…...

wordpress源代码下载/网络广告电话

一、在项目下新建RibbonForm 命名为&#xff1a;useSkin 二、添加引用DevExpress.OfficeSkinsDevExpress.UserSkins.BonusSkins三、将ribbonPage1的Text属性设置为&#xff1a;皮肤 ribbonPageGroup1的Text属性设置为&#xff1a;更换皮肤 在ribbonPageGroup1下新建个ribbonGa…...

淘宝客网站要备案吗/无锡百度推广代理商

认识BLE 5协议栈 —— 通用访问规范层 2017-04-20 by isyq 通用访问规范GAP&#xff08;Generic Access Profile&#xff09;是BLE设备内部功能对外的接口层&#xff0c;它规定了三个方面&#xff1a;GAP角色、模式和规程、安全问题。 GAP层将设备分为四种角色&#xff0c;分…...

竭诚网络网站建设价格/培训机构不退钱最怕什么举报

...