AOP执行顺序:
① 新建Maven工程,pom.xml如下:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.9.RELEASEversion>
<relativePath/>
parent>
<groupId>com.lungroupId>
<artifactId>HelloSpringBootartifactId>
<version>1.0.0-SNAPSHOTversion>
<packaging>jarpackaging>
<name>HelloSpringBootname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.1.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-accessartifactId>
<version>1.1.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.1.3version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>3.1.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
<dependency>
<groupId>org.redissongroupId>
<artifactId>redissonartifactId>
<version>3.13.4version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId><scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
② 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
③ 接口CalcService
public interface CalcService {
public int div(int x, int y);
}
④ 接口实现类CalcServiceImpl新加@Service
import org.springframework.stereotype.Service;
@Service
public class CalcServiceImpl implements CalcService {
@Override
public int div(int x, int y) {
int result = x / y;
System.out.println("===>CalcServiceImpl被调用,计算结果为:" + result);
return result;
}
}
⑤ 新建一个切面类MyAspect并为切面类新增两个注解:
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.lun.interview.service.CalcServiceImpl.*(..))")
public void beforeNotify() {
System.out.println("********@Before我是前置通知");
}
@After("execution(public int com.lun.interview.service.CalcServiceImpl.*(..))")
public void afterNotify() {
System.out.println("********@After我是后置通知");
}
@AfterReturning("execution(public int com.lun.interview.service.CalcServiceImpl.*(..))")
public void afterReturningNotify() {
System.out.println("********@AfterReturning我是返回后通知");
}
@AfterThrowing(" execution(public int com.lun.interview.service.CalcServiceImpl.*(..))")
public void afterThrowingNotify() {
System.out.println("********@AfterThrowing我是异常通知");
}
@Around(" execution(public int com.lun.interview.service.CalcServiceImpl.*(..))")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object retvalue = null;
System.out.println("我是环绕通知之前AAA");
retvalue = proceedingJoinPoint.proceed();
System.out.println("我是环绕通知之后BBB");
return retvalue ;
}
}
⑥ 测试类
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.lun.interview.service.CalcService;
@SpringBootTest
@RunWith(SpringRunner.class)
public class AopTest {
@Resource
private CalcService calcService;
@Test
public void testAop4() {
System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //
SpringVersion.getVersion(), SpringBootVersion.getVersion()));
calcService.div(10, 2);
}
}
⑦ aop 测试结果
输出结果:
Spring Verision : 4.3.13.RELEASE, Sring Boot Version : 1.5.9.RELEASE.
我是环绕通知之前AAA
********@Before我是前置通知
===>CalcServiceImpl被调用,计算结果为:5
我是环绕通知之后BBB
********@After我是后置通知
********@AfterReturning我是返回后通知
⑧ 修改测试类,让其抛出算术异常类:
@SpringBootTest
@RunWith(SpringRunner.class)
public class AopTest {
@Resource
private CalcService calcService;
@Test
public 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
at com.lun.interview.service.CalcServiceImpl.div(CalcServiceImpl.java:10)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
...
① 修改POM
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.3.RELEASEversion>
<relativePath/>
parent>
<groupId>com.lungroupId>
<artifactId>HelloSpringBootartifactId>
<version>1.0.0-SNAPSHOTversion>
<packaging>jarpackaging>
<name>HelloSpringBootname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>3.1.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
<dependency>
<groupId>org.redissongroupId>
<artifactId>redissonartifactId>
<version>3.13.4version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId><scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
② 修改测试类
import javax.annotation.Resource;
import org.junit.jupiter.api.Test;
//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.lun.interview.service.CalcService;
@SpringBootTest
//@RunWith(SpringRunner.class)
public class AopTest {
@Resource
private CalcService calcService;
@Test
public void testAop5() {
System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //
SpringVersion.getVersion(), SpringBootVersion.getVersion()));
System.out.println();
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
④ 修改测试类,让其抛出算术异常类:
@SpringBootTest
public class AopTest {
@Resource
private CalcService calcService;
...
@Test
public void testAop5() {
System.out.println(String.format("Spring Verision : %s, Sring Boot Version : %s.", //
SpringVersion.getVersion(), SpringBootVersion.getVersion()));
System.out.println();
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
at com.lun.interview.service.CalcServiceImpl.div(CalcServiceImpl.java:10)
at com.lun.interview.service.CalcServiceImpl$$FastClassBySpringCGLIB$$355acbc4.invoke()
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
在 Spring 容器中,为了提高 bean 实例化的效率,采用了三级缓存机制来管理 bean 实例化过程中的缓存。通过使用三级缓存,Spring 可以实现对 bean 实例化过程中间状态的缓存,从而提高了 bean 的创建速度和程序的性能。同时,也为我们提供了更好的理解和掌握 Spring 中 bean 的创建流程和机制的方式。
在 Spring 容器中,三级缓存主要包括如下三个 Map:
这三个Map 的主要异同点如下:
① 循环依赖是指两个或多个 bean 之间相互依赖,形成了一个闭环。 比如 bean A 依赖 bean B,而 bean B 也依赖 bean A,这样就形成了循环依赖。
② Spring 检测循环依赖主要通过三级缓存和构造函数注入来实现。 当 Spring 创建一个 bean 实例时,会首先检查是否存在该 bean 的二级缓存(earlySingletonObjects)中的对象,如果存在,则将其返回。否则,会从一级缓存(singletonObjects)中查找,如果也不存在,则需要创建该 bean 实例。
当创建该 bean 实例时,Spring 会先将用于创建该 bean 的 Factory 对象放入三级缓存(singletonFactories)中,并标记 bean 正在创建,然后继续创建 bean 所依赖的其他 bean 实例。当创建依赖 bean B 时,发现 bean B 也依赖 bean A,此时 Spring 需要提前返回一个 “早期” bean B 实例,以避免死循环。
在这种情况下,如果 bean B 和 bean A 都采用构造函数注入,则 Spring 会抛出 BeanCurrentlyInCreationException 异常,提示存在循环依赖。如果 bean A 使用了 setter 注入,则 Spring 会创建一个"空壳" 的 bean A 实例,并返回,以避免循环依赖问题。
总的来说,Spring 通过三级缓存和构造函数注入来检测循环依赖问题,并且在发现循环依赖时,会及时抛出异常或者创建空壳实例以避免死循环问题的出现。
③ 在 Spring 开发中,常见的循环依赖异常有两种:
这两种异常都是由于循环依赖引起的。如果 bean 之间存在循环依赖关系,则需要通过适当的配置或者设计来解决。一般来说,使用构造函数注入方式并尽量避免循环依赖是比较好的选择。也可以考虑使用 @Lazy 注解延迟加载 bean 或者使用 @DependsOn 注解显式指定 bean 的依赖顺序等方式来解决循环依赖问题。
在 Spring 中,@Lazy 注解是一种用于延迟加载 bean 的注解。当使用 @Lazy 注解标记一个 bean 时,Spring 容器将推迟实例化它,直到该 bean 第一次被请求使用时才会进行初始化。
@Lazy 注解的实现原理比较简单,其本质是在 bean 的注册过程中,将需要延迟加载的 bean 标记为“懒加载”状态。这样,当容器启动时,它将创建一个代理对象来代替实际的 bean,然后在第一次调用该 bean 时才会触发实际的 bean 创建和初始化过程。
具体来说,当使用 @Lazy 注解标注一个 bean 时,Spring 容器将会在 BeanDefinition 中设置一个 lazyInit 标志位,表示该 bean 是否需要延迟加载。在创建该 bean 的代理对象时,Spring 会将 lazyInit 标志位传递给代理对象,并在代理对象中实现对被代理对象的延迟加载,也就是在首次调用代理对象时,通过 getObject() 方法获取真正的 bean 实例,并进一步执行其生命周期方法。
在多数情况下,使用 @Lazy 注解可以提高系统的性能表现,减少应用启动时间和内存占用,特别是当有部分 bean 比较耗时或者内存占用较大时,可以利用延迟加载策略来避免过早创建对象带来的性能问题。
在 Spring 中,@DependsOn 注解用于指定 bean 之间的依赖关系,表示需要等待某个 bean 初始化完成后再初始化当前 bean。具体来说,当一个 bean 定义了 @DependsOn 注解时,Spring 容器将优先初始化该 bean 所依赖的 bean,并确保它们都已经完成了初始化后才会初始化当前 bean。
@DependsOn 注解的底层原理是在 bean 构建过程中的初始化阶段,通过判断当前 bean 是否存在依赖关系,如果存在,则先初始化依赖的 bean,然后再初始化当前 bean。所以,在使用 @DependsOn 注解时,需要注意避免形成循环依赖,否则可能导致启动失败或其他异常问题。
具体地,@DependsOn 注解的实现原理类似于 @Autowired 注解,底层都是利用 BeanFactory 和 BeanDefinition 来完成的。在容器启动时,首先会根据配置文件或注解扫描的方式创建 BeanFactory,接着创建 BeanDefinition,并在 BeanDefinition 中设置依赖关系。在加载 bean 的过程中,Spring 容器会在 BeanDefinition 中查找与当前 bean 存在依赖关系的 bean,然后先按照依赖顺序初始化它们,最后再初始化当前 bean。这样才能保证调用 bean 实例方法时,所依赖的其他 bean 实例已经完全初始化完成,从而避免出现 NPE 等问题。
总之,@DependsOn 注解的底层原理是在 bean 的注册过程中,通过依赖关系来确定 bean 的初始化顺序,并保证它们按照正确的顺序进行初始化。它和 @Lazy 注解一样,都是用来优化系统性能和解决特定场景下的问题的有效手段。
在 Spring 中,使用 @Autowired 注解来自动装配其他 bean 时,底层实现原理是通过 Java 的反射机制来实现的。
具体来说,在执行加载 bean 的过程中,Spring 容器会默认扫描包路径下的所有类和注解,并将它们注册到一个内部的 BeanDefinitionRegistry 中。当使用 @Autowired 注解时,Spring 容器会在这个注册表中查找与被注入的 bean 类型匹配的 bean,然后通过反射调用其 setter 方法或者字段来完成自动装配。
在进行自动装配时,Spring 支持多种不同的装配方式,包括构造函数注入、setter 方法注入、字段注入等。在使用 @Autowired 注解时,默认使用的是根据类型自动装配的方式,即从容器中查找与被注入的 bean 类型匹配的 bean,并将其注入到被注入的 bean 中。
除了 @Autowired 注解外,Spring 还提供了其他多个装配注解,例如 @Resource、@Inject 等,它们都是基于 Java 的反射机制实现的,但提供不同的装配方式和粒度,可以根据具体的业务需求进行选择和使用。
在 Spring 中,循环依赖主要是通过 singleton scope 的 bean 来进行解决。因为 singleton scope 的 bean 可以被缓存,所以 Spring 能够在创建 bean 的过程中检测到循环依赖,并提供一种解决方案来打破循环依赖。
然而,对于 prototype scope 的 bean,Spring 无法缓存这些对象,也无法有效地解决依赖问题。如果两个或多个 prototype scope 的 bean 存在循环依赖关系,那么 Spring 将无法得知它们之间的依赖关系,从而导致循环依赖问题不可避免。
这是因为 prototype scope 的 bean 在每次被请求时都会创建一个新的实例。如果一个 prototype scope 的 bean 依赖于另一个 prototype scope 的 bean,那么每次创建 bean 实例时都会重新创建一个新的依赖 bean 实例,从而无法建立稳定的依赖关系,导致循环依赖问题无法解决。
因此,在开发过程中,如果需要使用 prototype scope 的 bean,并且存在循环依赖关系,那么需要采用其他方式来解决该问题,例如将依赖关系转换为单向的、避免使用 prototype scope 的 bean 或者手动管理 bean 的生命周期等。
通常来说,如果问Spring容器内部如何解决循环依赖,一定是指默认的单例Bean中,属性互相引用的场景。
两种注入方式对循环依赖的影响,循环依赖官网说明:
Circular dependencies
If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.
For example: Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws aBeanCurrentlyInCreationException
.
One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.
Unlike the typical case (with no circular dependencies), a circular dependency between bean A and bean B forces one of the beans to be injected into the other prior to being fully initialized itself (a classic chicken-and-egg scenario).link
结论:我们AB循环依赖问题只要A的注入方式是setter且singleton ,就不会有循环依赖问题。
Spring容器循环依赖报错演示BeanCurrentlylnCreationException。
循环依赖现象在spring容器中注入依赖的对象,有2种情况:
@Component
public class ServiceB{
private ServiceA serviceA;
public ServiceB(ServiceA serviceA){
this.serviceA = serviceA;
}
}
@Component
public class ServiceA{
private ServiceB serviceB;
public ServiceA(ServiceB serviceB){
this.serviceB = serviceB;
}
}
public class ClientConstructor{
public static void main(String[] args){
new ServiceA(new ServiceB(new ServiceA()));//这会抛出编译异常
}
}
@Component
public class ServiceBB{
private ServiceAA serviceAA;
public void setServiceAA(ServiceAA serviceAA){
this.serviceAA = serviceAA;
System.out.println("B里面设置了A");
}
}
@Component
public class ServiceAA{
private ServiceBB serviceBB;
public void setServiceBB(ServiceBB serviceBB){
this.serviceBB = serviceBB;
System.out.println("A里面设置了B");
}
}
public class ClientSet{
public static void main(String[] args){
//创建serviceAA
ServiceAA a = new ServiceAA();
//创建serviceBB
ServiceBB b = new ServiceBB();
//将serviceA入到serviceB中
b.setServiceAA(a);
//将serviceB法入到serviceA中
a.setServiceBB(b);
}
}
输出结果:
B里面设置了A
A里面设置了B
① beans:A,B
public class A {
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
System.out.println("A call setB.");
}
}
public class B {
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
System.out.println("B call setA.");
}
}
② 运行类
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ClientSpringContainer {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
A a = context.getBean("a", A.class);
B b = context.getBean("b", B.class);
}
}
默认的单例(Singleton)的场景是支持循环依赖的,不报错:
① beans.xml
<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/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="a" class="com.lun.interview.circular.A">
<property name="b" ref="b">property>
bean>
<bean id="b" class="com.lun.interview.circular.B">
<property name="a" ref="a">property>
bean>
beans>
② 输出结果
00:00:25.649 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6d86b085
00:00:25.828 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [beans.xml]
00:00:25.859 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'a'
00:00:25.875 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'b'
B call setA.
A call setB.
原型(Prototype)的场景是不支持循环依赖的,会报错。
① beans.xml
<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/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="a" class="com.lun.interview.circular.A" scope="prototype">
<property name="b" ref="b">property>
bean>
<bean id="b" class="com.lun.interview.circular.B" scope="prototype">
<property name="a" ref="a">property>
bean>
beans>
② 输出结果
00:01:39.904 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6d86b085
00:01:40.062 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [beans.xml]
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'a' defined in class path resource [beans.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 [beans.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?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1697)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1442)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:342)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1115)
at com.lun.interview.circular.ClientSpringContainer.main(ClientSpringContainer.java:10)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined in class path resource [beans.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?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1697)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1442)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:342)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
... 9 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:268)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
... 17 more
(spring内部通过3级缓存来解决循环依赖) - DefaultSingletonBeanRegistry
只有单例的bean会通过三级缓存提前暴露来解决循环依赖的问题,而非单例的bean,每次从容器中获取都是一个新的对象,都会重新创建,所以非单例的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);
...
}
实例化 - 内存中申请一块内存空间,如同租赁好房子,自己的家当还未搬来。
初始化属性填充 - 完成属性的各种赋值,如同装修,家具,家电进场。
3个Map和四大方法,总体相关对象
第一层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两对象在三级缓存中的迁移说明
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
DEBUG一步一步来,scope默认为singleton
① 从运行类启航
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ClientSpringContainer {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
A a = context.getBean("a", A.class);
B b = context.getBean("b", B.class);
}
}
package org.springframework.context.support;
...
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
//源于AbstractXmlApplicationContext
//->AbstractRefreshableConfigApplicationContext
//->AbstractRefreshableApplicationContext
//->AbstractApplicationContext的refresh()
refresh();
}
}
}
package org.springframework.context.support;
...
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
...
}
package org.springframework.context.support;
...
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
implements BeanNameAware, InitializingBean {
...
}
package org.springframework.context.support;
...
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
...
}
package org.springframework.context.support;
...
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
...
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
--------------->//<---------------------重点关注点是这里
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
------->//<---------------------重点关注点是这里
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
}
beanFactory是ConfigurableListableBeanFactory
DefaultListableBeanFactory实现了ConfigurableListableBeanFactory接口
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
//根据上下文beanNames为[a, b]
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {//遍历a,b
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
------------------->//<---------------------重点关注点是这里
//源于AbstractAutowireCapableBeanFactory
//->AbstractBeanFactory的getBean()
getBean(beanName);
}
}
}
------------------------------下面可略读---------------------------
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
}
package org.springframework.beans.factory.support;
...
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
...
}
package org.springframework.beans.factory.support;
...
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
...
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//name为a
String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
------->//<---------------------重点关注点是这里
------->//<---------------------重点关注点是这里
------->//<---------------------重点关注点是这里
//源于FactoryBeanRegistrySupport
//->DefaultSingletonBeanRegistry的getSingleton()
//DefaultSingletonBeanRegistry也就是上文谈论的三级缓存所在类
//本章节末有getSingleton()源码
//最后getSingleton返回null
Object sharedInstance = getSingleton(beanName);
//sharedInstance为null,下面if语块不执行
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//不执行下面if语块
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
//parentBeanFactory为null,不执行下面if语块
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
//下面方法返回Root bean: class [com.lun.interview.circular.A];
//scope=singleton; abstract=false; lazyInit=false;
//autowireMode=0; dependencyCheck=0; autowireCandidate=true;
//primary=false; factoryBeanName=null; factoryMethodName=null;
//initMethodName=null; destroyMethodName=null;
//defined in class path resource [beans.xml]
//重点关注scope=singleton
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
//dependsOn返回null,不执行下面if语块
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
//mbd.isSingleton()返回true,执行下面if语块
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
--------------------------->//<---------------------重点关注点是这里
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
----------------------------下面代码可略读---------
------------------
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
}
AbstractBeanFactory继承了FactoryBeanRegistrySupport
package org.springframework.beans.factory.support;
...
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
...
}
FactoryBeanRegistrySupport继承了DefaultSingletonBeanRegistry,DefaultSingletonBeanRegistry也就是前文讨论三级缓存所在的类。
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);
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
* Return the (raw) singleton object registered under the given name.
* Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//beanName为a,查找缓存,显然返回null
Object singletonObject = this.singletonObjects.get(beanName);
//singletonObject为null,下面if语块不执行
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
//返回null
return singletonObject;
}
}
本节太晕了,画个图理解
再次A / B两对象在三级缓存中的迁移说明:
Spring创建 bean主要分为两个步骤,创建原始bean对象,接着去填充对象属性和初始化。
每次创建 bean之前,我们都会从缓存中查下有没有该bean,因为是单例,只能有一个。
当我们创建 beanA的原始对象后,并把它放到三级缓存中,接下来就该填充对象属性了,这时候发现依赖了beanB,接着就又去创建beanB,同样的流程,创建完beanB填充属性时又发现它依赖了beanA又是同样的流程,不同的是:这时候可以在三级缓存中查到刚放进去的原始对象beanA,所以不需要继续创建,用它注入 beanB,完成 beanB的创建。既然 beanB创建好了,所以 beanA就可以完成填充属性的步骤了,接着执行剩下的逻辑,闭环完成。
Spring 解决循环依赖依靠的是Bean的"中间态"这个概念,而这个中间态指的是已经实例化但还没初始化的状态—>半成债。实例化的过程又是通过构造器创建的,如果A还没创建好出来怎么可能提前曝光,所以构造器的循环依赖无法解决。
Spring为了解决单例的循坏依赖问题,使用了三级缓存:
其中一级缓存为单例池(singletonObjects)。
二级缓存为提前曝光对象(earlySingletonObjects)。
三级级存为提前曝光对象工厂(singletonFactories) 。
假设A、B循环引用,实例化A的时候就将其放入三级缓存中,接着填充属性的时候,发现依赖了B,同样的流程也是实例化后放入三级缓存,接着去填充属性时又发现自己依赖A,这时候从缓存中查找到早期暴露的A,没有AOP代理的话,直接将A的原始对象注入B,完成B的初始化后,进行属性填充和初始化,这时候B完成后,就去完成剩下的A的步骤,如果有AOP代理,就进行AOP处理获取代理后的对象A,注入B,走剩下的流程。