参考:

AspirantPeng : Bean的生命周期

 : Spring源码学习--Aware相关接口

Water : Spring 如何解决 Bean 的循环依赖(循环引用)

 :哪些循环依赖问题Spring解决不了?

三友的java日记 : @Async注解的坑,小心

概念

什么是 IOC ?

IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建、依赖,反转给容器来帮忙实现。我们需要创建一个容器,同时需要一种描述来让容器知道要创建的对象与对象的关系。这个描述最具体的表现就是我们所看到的配置文件。

什么是 DI ?

DI(Dependency Injection,依赖注入)就是指对象被动接受依赖类而不自己主动去找,换句话说,就是指对象不是从容器中查找它依赖的类,而是在容器实例化对象时主动将它依赖的类注入给它

 

BeanFactory 和 ApplicationContext

BeanFactory ApplicationContext
最基本的IOC容器,提供管理Bean的基本功能 高级容器,继承 extends BeanFactory,添加了一些高级功能
仅支持 Singleton 和 Prototype bean 范围 支持所有类型的 bean 范围,例如 Singleton、Prototype、Request、Session 等。
不支持注释。仅支持 xml 支持 Bean 自动装配中基于注释的配置
不提供 messaging(i18n 或国际化)功能 ApplicationContext 接口扩展了 MessageSource 接口,因此它提供 messaging(i18n 或国际化)功能。
不支持事件发布功能。 ApplicationContext 中的事件处理是通过 ApplicationEvent 类和 ApplicationListener 接口提供的。

调用 getBean() 方法时,BeanFactory 将创建一个 bean 对象,

从而使其成为延迟初始化

ApplicationContext 仅在启动时加载所有 bean 并创建对象,从而使其进行热切初始化。

需要较少的内存。对于基本功能已经足够并且内存消耗很关键的独立应用程序,

我们可以使用BeanFactory。

提供所有基本功能和高级功能,包括一些面向企业应用程序的功能,因此需要更多内存。

 

Bean 的几种注入容器的方式

1、@Configuration + @Bean

@Configuration用来声明一个配置类,然后在方法上使用 @Bean 注解,会将方法返回的对象加入到Spring容器中。

@Configuration
@ConditionalOnClass(value = {RestTemplate.class, HttpClient.class})
public class RestTemplateConfiguration {
    @Value("${restclient.maxTotalConnect:0}")
    private int maxTotalConnect; //连接池的最大连接数默认为0
    @Value("${restclient.maxConnectPerRoute:200}")
    private int maxConnectPerRoute; //单个主机的最大连接数
    @Value("${restclient.connectTimeout:2000}")
    private int connectTimeout; //连接超时默认2s
    @Value("${restclient.readTimeout:30000}")
    private int readTimeout; //读取超时默认30s
    @Value("${restclient.connectionRequestTimeout:5000}")
    private  int connectionRequestTimeout; //客户端和服务器建立连接的timeout
    @Value("${restclient.socketTimeout:5000}")
    private  int socketTimeout;

   
    //初始化httpClient,并加入spring的Bean工厂,由spring统一管理
    @Bean("httpClient")
    @ConditionalOnMissingBean(name = "httpClient")
    public CloseableHttpClient httpClient() {

        RequestConfig requestConfig  = RequestConfig.custom()
                .setSocketTimeout(this.socketTimeout)
                .setConnectTimeout(this.connectTimeout)
                .setConnectionRequestTimeout(this.connectionRequestTimeout)
                .build();

        CloseableHttpClient client = HttpClientBuilder.create().setMaxConnTotal(this.maxTotalConnect)
                .setMaxConnPerRoute(this.maxConnectPerRoute).setDefaultRequestConfig(requestConfig).build();

        return client;
    }

2、通过包扫描特定注解的方式

@ComponentScan 放置在我们的配置类上,然后可以指定一个路径,进行扫描带有特定注解的bean,然后加至容器中。

特定注解包括@Controller、@Service、@Repository、@Component

@Service
public class Person {
    //...
}
 
@ComponentScan(basePackages = "com.dabin.test.*")
public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);
    }
}

3、implements FactoryBean 接口

我们的Bean工厂由于也是对象的一种,所以我们要把它加上 @Component 注解注册进Spring容器中

@Component
public class FactoryBean_test implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new User();
    }
 
    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

它实际上会注册进两个Bean对象,一个是我们的工厂对象,另一是我们生产出来的对象。

        //获取生产出来的对象
        User user1 = applicationContext.getBean("user",User.class);
        //获取工厂对象
        FactoryBean_test factoryBean_test = applicationContext.getBean("&user",FactoryBean_test.class);

 

Bean 的生命周期

一、Bean 核心生命周期:init 和 destory 

虽然spring提供了大量Bean级生命周期接口和容器级生命空间接口来扩展bean的生命周期,但bean的核心生命周期只有四个阶段:

bean实例化,依赖注入,自定义init方法,自定义destroy方法

  • bean 是单例才会调用 destroy,是多例 prototype 不会。多例的 bean 创建成功后就交给用户管理了,不由 spring 管理

init 和 destroy 有下面三种配置方法:

1.通过在 @Bean 注解 或在 bean 的 xml 配置 init/destroy 方法

@Bean 注解里可以定义 init 方法 和 destroy 方法。

如下面这个数据源的,可以在 initMethod = "init", destroyMethod = "close" 两个方法里进行 druid 的创建和销毁

@Configuration
public class DataSourceConfiguration {

    /**
     * The constant TEST_DRUID_PREFIX.
     */
    private static final String TEST_DRUID_PREFIX = "test.datasource";

    @Bean(name = "testDataSource", initMethod = "init", destroyMethod = "close")
    @ConditionalOnMissingBean(name = "testDataSource")
    @ConfigurationProperties(UCC_DRUID_PREFIX)
    public CoreDataSourceBean testDataSource(
        @Qualifier("testDruidDataSourceProperties") DruidDataSourceProperties druidDataSourceProperties) {
        DruidDataSource druidDataSource = new DruidDataSourceBuilder().properties(druidDataSourceProperties).build();
        return new CoreDataSourceBean(druidDataSource);
    }

xml 配置 bean 属性

<!DOCTYPE
    beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
        "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
             
<beans>
    <bean id="hw" class="beans.HelloWorld"
            init-method="init" destroy-method="destroy"/>
</beans>

2.在方法上加 @PostConstruct 和 @PreDestroy

这是 java 的注解,可以先忽略

@PostConstruct
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
        // load driver
        Class.forName(driver);

        // get a connection
        con = DriverManager.getConnection(url, userName, password);

        // execute query
        stmt = con.createStatement();
    }

public void closeConnection() throws SQLException {
        con.close();
    }

@PreDestroy
public void destroy() throws SQLException {
        closeConnection();
    }

3.通过实现接口 InitializingBean 和 DisposableBean

并重写 afterPropertiesSet() 和 destroy() 方法

// Java program to create a bean
// in the spring framework
package beans;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
 
// HelloWorld class which implements the
// interfaces
public class HelloWorld implements InitializingBean,DisposableBean {
 
    @Override
    // It is the init() method of our bean and it gets invoked on bean instantiation
    public void afterPropertiesSet() throws Exception
    {
        System.out.println("Bean HelloWorld has been instantiated and I'm the init() method");
    }
 
    @Override
    // This method is invoked just after the container is closed
    public void destroy() throws Exception
    {
        System.out.println("Container has been closed and I'm the destroy() method");
    }
}

 

二、容器级生命周期接口:BeanPostProcessor

它允许自定义修改 Spring Bean Factory 创建的新 bean 实例。如果我们想要实现一些自定义逻辑,例如在 Spring 容器完成实例化、配置和初始化 bean 后检查标记接口或用代理包装 bean,我们可以插入 BeanPostProcessor 实现。

BeanPostProcessor 接口包含两个回调方法如下: 

  1. postProcessBeforeInitialization() 方法
  2. postProcessAfterInitialization() 方法

BeanPostProcessor 也是作为bean注册到spring容器中的,Spring会保证BeanPostProcessor在业务Bean之前初始化完成。

// Java Program to Illustrate CustomProcessor Class
package com.geeks.beans;

// Importing required classes
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

// Class
// Implementing BeanPostProcessor interface
public class CustomProcessor implements BeanPostProcessor {

    // Method 1
    public Object postProcessBeforeInitialization(
        Object bean, String beanName) throws BeansException
    {
        System.out.println("postProcessBeforeInitialization() is called for EmployeeImpl");
        return bean;
    }

    // Method 2
    public Object postProcessAfterInitialization(
        Object bean, String beanName) throws BeansException
    {
        System.out.println("postProcessAfterInitialization() is called for EmployeeImpl");
        return bean;
    }
}

可以配置多个 BeanPostProcessor,并且只有我们配置的 BeanFactoryPostProcessor 同时实现了 Ordered 接口的话,还可以控制这些 BeanPostProcessor 执行的顺序。

【每个 bean 】初始化前后,就会【依次串行】调用这些 BeanPostPocessor

AbstractAutowireCapableBeanFactory 类,doCreateBean-----initializeBean----applyBeanPostProcessorsBeforeInitialization

  @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

 

三、Bean 级的其它补充

Spring源码中接口以Aware结尾的接口(XXXAware),在Spring中表示对XXX可以感知,通俗点解释就是:如果在某个类里面想要使用spring的一些东西,就可以通过实现XXXAware接口告诉Spring,Spring看到后就会给你送过来,而接收的方式是通过实现接口唯一方法set-XXX。

比如:有一个类想要使用当前的 ApplicationContext,那么我们只需要让它实现ApplicationContextAware接口,然后实现接口中的唯一方法

void setApplicationContext(ApplicationContext applicationContext)

就可以了,spring会自动调用()这个方法将 applicationContext传给我们,我们只需要接受就可以了,并可以用接收到的内容做一些业务逻辑。

BeanNameAware

public interface BeanNameAware extends Aware {
    void setBeanName(String var1);
}

BeanClassLoaderAware

public interface BeanClassLoaderAware extends Aware {
    void setBeanClassLoader(ClassLoader var1);
}

如果一个 Bean 实现了 Aware 接口,那么就会 调用它实现的 Aware 接口的相关方法

AbstractAutowireCapableBeanFactory 类,doCreateBean-----initializeBean----invokeAwareMethods

  private void invokeAwareMethods(String beanName, Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware)bean).setBeanName(beanName);
            }

            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = this.getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);
                }
            }

            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware)bean).setBeanFactory(this);
            }
        }
    }

注意 init方法 和 destroy方法,都是调用 InitializingBean 和 DisposableBean 的接口方法 在定义的 init 和 destroy 前面

如果Bean是多例(原型模式 prototype)的话,在 BeanPostProcessor#after 之后,容器将Bean返回给用户,剩下的生命周期由用户控制。而单例会一直在Map缓存中。

代码如下:每个 bean 初始化前后,分别、依次串行调用 BeanPostProcessor 的 BeforeInitialization 和 AfterInitialization

   @SuppressWarnings("deprecation")
    protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        invokeAwareMethods(beanName, bean);

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            invokeInitMethods(beanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

 

 

Bean的作用域

  • 单例对象:scope="singleton",默认值,一个应用只有一个对象的实例。它的作用范围就是整个引用。
    • 生命周期:
      • 对象出生:当应用加载,创建容器时,对象就被创建了。
      • 对象活着:只要容器在,对象一直活着。
      • 对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
  • 多例对象(原型):scope="prototype":每次访问对象时,都会重新创建对象实例。
    • 生命周期:
      • 对象出生:当使用对象时,创建新的对象实例。
      • 对象活着:只要对象在使用中,就一直活着。
      • 对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。
  • request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
  • session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
  • global session:WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于session.

 

依赖注入

Spring的自动装配有三种模式:byType(根据类型),byName(根据名称)、constructor(根据构造函数)。

@Autowired 和 @Resource 的区别

主要体现在以下 5 点:

  1. 来源不同:@Autowired 是 Spring 定义的注解,而 @Resource 是 Java 定义的注解
  2. 依赖查找的顺序不同:@Autowired 是先根据类型(byType)查找,如果存在多个 Bean 再根据名称(byName)进行查找。@Resource 则相反,先根据名称(找不到)再根据类型。
  3. 支持的参数不同:@Autowired 只支持设置一个 required 的参数,而 @Resource 支持 name type 等7个参数
  4. 依赖注入的用法不同:@Autowired 支持属性注入、构造方法注入和 Setter 注入,而 @Resource 只支持属性注入和 Setter 注入

@Qualifier意思是合格者,一般跟 @Autowired 配合使用,需要指定一个 bean 的名称,如果 @Autowired 找到多个同类型的 bean,通过 @Qualifier 指定的bean名称就能找到需要装配的bean。

属性注入、构造方法注入、setter 注入

属性注入

@Service
public class UserExtService {
    // 属性注入
    @Autowired
    private UserService userService;
 
    //......
}

构造方法注入

@Service
public class UserExtService {
    // 构造方法注入
    private UserService userService;
 
    @Autowired
    public UserExtService(UserService userService) {
        this.userService = userService;
    }

    //......
}

setter 注入

@Service
public class UserExtService {
    // Setter 注入
    private UserService userService;
 
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

     //.....
}

 @Autowired 原理(MergedBeanDefinitionPostProcessor)

Spring 中通过 AutowiredAnnotationBeanPostProcessor来解析注入注解为目标注入值。

  • 该类继承自 InstantiationAwareBeanPostProcessorAdapter:该类继承了 BeanPostProcessor,主要方法是 postProcessPropertyValues。用来进行依赖注入。在 doCreateBean 的 populateBean 方法中,会依次串行调用 instance of 这个类的所有 BeanPostProcessor。
  • 该类实现了 MergedBeanDefinitionPostProcessor: 该接口继承了 BeanPostProcessor,主要方法是 postProcessMergedBeanDefinition 。用来解析和设置 @Autowired 相关的依赖的元数据。在 doCreateBean 实例化后会依次串行调用 instance of 这个接口的所有 BeanPostProcessor。

PriorityOrdered, BeanFactoryAware等接口,重写的方法将在 IOC 创建每个bean实例后被调用。

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {

    // BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器
    BeanWrapper instanceWrapper = null;
    // 单例模型,则从未完成的 FactoryBean 缓存中删除
    if (mbd.isSingleton()) {anceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }

    // 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }

    // .......

synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { // 对 @Autowired 等依赖注解的元信息进行查找和解析。依次串行调用实现了 MergedBeanDefinationPostProcessor 接口的 BeanPostProcessor applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } //... /* * 开始初始化 bean 实例对象 */ Object exposedObject = bean; try { // 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性 // 递归进行依赖注入。依次串行调用继承了 InstantitionAwareBeanPostProcessor 的所有 BeanPostProcessor populateBean(beanName, mbd, instanceWrapper);      // 注入 Aware 相关的对象      // 调用 后置处理器 BeanPostProcessor 里面的postProcessBeforeInitialization方法      // 调用 initialzingBean,调用实现的 afterPropertiesSet()      // 调用 init-mothod,调用相应的init方法      // 调用 后置处理器 BeanPostProcessor 里面的调用实现的postProcessAfterInitialization方法      exposedObject = initializeBean(beanName, exposedObject, mbd);   }   catch (Throwable ex) {      if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {         throw (BeanCreationException) ex;      }     else {       throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } //..... return exposedObject; } }
  • 该类实现了 MergedBeanDefinitionPostProcessor: 该接口继承了 BeanPostProcessor,主要方法是 postProcessMergedBeanDefinition 。用来解析和设置 @Autowired 相关的依赖的元数据。在 doCreateBean 实例化后会依次串行调用 instance of 这个接口的所有 BeanPostProcessor。的 postProcessMergedBeanDedination 方法。
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
        Iterator var4 = this.getBeanPostProcessors().iterator();

        while(var4.hasNext()) {
            BeanPostProcessor bp = (BeanPostProcessor)var4.next();
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor)bp;
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }

    }
  • 该类继承自 InstantiationAwareBeanPostProcessorAdapter:该类继承了 BeanPostProcessor,主要方法是 postProcessPropertyValues。用来进行依赖注入。在 doCreateBean 的 populateBean 方法中,会依次串行调用 instance of 这个类的所有 BeanPostProcessor。的 postProcessAfterInstantiation 方法。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
        } else {
            if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
                Iterator var4 = this.getBeanPostProcessors().iterator();

                while(var4.hasNext()) {
                    BeanPostProcessor bp = (BeanPostProcessor)var4.next();
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
                        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                            return;
                        }
                    }
                }
            }
//......
}

 

 

 三级缓存解决循环依赖

循环依赖的发生

@Component
public class A {
    @Autowired
    private B b;
    
}
@Component
public class B {
    @Autowired
    private A a;
    
}

A 和 B 要完成 实例化、依赖注入、初始化 三个步骤后放入一级缓存 singletonObjects

原始对象 A 实例化完成,依赖注入需要注入 B 时,发现 B 不存在,就要实例化 B 

B 实例化完成后,要接着进行依赖注入,需要注入 A,这时 A 还没完成依赖注入,在一级缓存里找不到

这样,A 和 B 虽然都进行了实例化,但是都完成不了依赖注入,没法成功创建加入一级缓存

三级缓存介绍

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    private final Map<String, Object> earlySingletonObjects = new HashMap(16);
  //......
缓存名称 源码名称 存放内容 作用 添加或移除的时机
一级缓存 singletonObjects bean名称-bean对象(依赖注入完成,初始化也完成的bean)  存储单例的bean

添加:完成实例化、依赖注入、初始化,生成完整的 bean 后。同时移除二级或三级缓存

二级缓存 earlySingletonObjects bean名称-bean对象(只是实例化了的 bean,还未完成依赖注入和初始化) 解决循环依赖时,无法完成依赖注入,也就无法成功创建bean的问题 添加:在三级缓存中获取到时 ObjectFactory,得到的 代理对象 添加到二级缓存,并清理三级缓存。
三级缓存 singletonFactories bean名称-ObjectFactory<T>(代理工厂接口,有 T getBean(beanName) 方法可以创建对应代理对象) 使得循环依赖时,依赖双方,注入的都是代理后的对象 添加:通过 createBeanInstance 实例化Bean之后,调用populateBean 进行依赖注入之前。

实际上 一级 和 二级 缓存就能解决一般的 循环依赖问题

A 和 B 实例化后就放到 二级缓存 earlySingletonObjects 中。

这样原始对象 A 需要注入 B 时,发现 B 不存在,就实例化 B ,并放到 二级缓存 earlySingletonObjects 中。

接着 B 还要进行依赖注入,需要注入 A,这时 A 虽然再一级缓存中找不到,但是可以在二级缓存中找到。这样 B 就可以完成依赖注入,创建完成放入一级缓存。

接着再完成 A 的依赖注入,注入成功创建的 B ,A 也完成了创建。

但是 如果一个对象被增强了,即 是个代理对象, 这个时候就需要一个三级缓存

对象被增强后,那么需要四个步骤:实例化、依赖注入、初始化、生成代理对象

二级缓存时:

A实例化完成后放到二级缓存,开始依赖注入,发现B不存在

B开始实例化,注入二级缓存中刚实例化的A,B初始化完成后封装成代理对象(代理对象生成得晚)

A再将代理后的B注入,再做代理,那么代理A中的B就是代理后的B,但是代理后的B中的A是没用代理的A,这个没用代理的A 与最终 spring 容器中的 A 不相同

三级缓存时:

实例化后,将 ObjectFactory 放入三级缓存,这样需要注入时,首先获取三级缓存中的 ObjectFactory,通过它先创建一个代理对象,放入二级缓存

doCreateBean 三级缓存源码

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {

    // BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器
    BeanWrapper instanceWrapper = null;
    // 单例模型,则从未完成的 FactoryBean 缓存中删除
    if (mbd.isSingleton()) {anceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }

    // 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }

    // 创建实例对象(包装的)
    final Object bean = instanceWrapper.getWrappedInstance();
    // 包装的实例对象的类型
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    // 检测是否有后置处理
    // 如果有后置处理,则允许后置处理修改 BeanDefinition
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {// 对 @Autowired 等依赖注解的元信息进行查找和解析。依次串行调用实现了 MergedBeanDefinationPostProcessor 接口的 BeanPostProcessor
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    // 解决单例模式的循环依赖
    // 单例模式 & 允许循环依赖 & 当前单例 bean 是否正在被创建
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        // 三级缓存:提前将创建的 bean 实例加入到ObjectFactory 中
        // 这里是为了后期避免循环依赖
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    /*
     * 开始初始化 bean 实例对象
     */
    Object exposedObject = bean;
    try {
        // 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
        // 递归进行依赖注入。依次串行调用继承了 InstantitionAwareBeanPostProcessor 的所有 BeanPostProcessor
        populateBean(beanName, mbd, instanceWrapper);
     // 注入 Aware 相关的对象
     // 调用 后置处理器 BeanPostProcessor 里面的postProcessBeforeInitialization方法
     // 调用 initialzingBean,调用实现的 afterPropertiesSet()
      // 调用 init-mothod,调用相应的init方法
     // 调用 后置处理器 BeanPostProcessor 里面的调用实现的postProcessAfterInitialization方法
      exposedObject = initializeBean(beanName, exposedObject, mbd);
  } 
  catch (Throwable ex) {
     if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
        throw (BeanCreationException) ex;
     }        
    else {            
      throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
       }
   }
/** * 循环依赖处理 */ if (earlySingletonExposure) { // 获取 earlySingletonReference (先从一级获取,一级获取不到从二级,二级获取不到从三级,三级获取到ObjectFactory得到代理类放入二级,同时移除三级) Object earlySingletonReference = getSingleton(beanName, false); // 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空 if (earlySingletonReference != null) { // 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强 if (exposedObject == bean) { exposedObject = earlySingletonReference; } // 依赖注入 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } try { // 注册 bean registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; } }

DefaultSingletonBeanRegistry 中的 getSingleton 方法

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
         // 从一级缓存获得
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {
          // 一级缓存获取不到,从二级缓存获取
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
             // 二级缓存获取不到,从三级缓存获取                  
            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
              // 通过三级缓存的 ObjectFactory 生成代理对象
                        singletonObject = singletonFactory.getObject();
              // 将三级缓存生成的代理对象放入二级缓存                     
              this.earlySingletonObjects.put(beanName, singletonObject);
              // 从三级缓存中移除 ObjectFactory
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }

        return singletonObject;
    }

Spring 无法解决的循环依赖

1、@Async 增强的 Bean 的循环依赖

普通的 AOP 代理 Bean 的循环依赖,Spring 都是可以通过上述的 三级缓存 解决的。例如 用户自定义的 @Aspect 。

它们二者在三级缓存上的主要区别:

  • 普通的 AOP 代理都是通过 AnnotationAwareAspectJAutoProxyCreator 来生成代理类的,AnnotationAwareAspectJAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor 接口。可以早期暴露代理对象。
  • @Async 标记的类是通过 AbstractAdvisingBeanPostProcessor 来生成代理类的,AbstractAdvisingBeanPostProcessor 没有实现 SmartInstantiationAwareBeanPostProcessor 接口。

AbstractAutoProxyCreator 和 AbstractAdvisingBeanPostProcessor 都实现了 BeanPostProcessor 接口的 postProcessAfterInitialization 方法,在对象初始化完成后会回调这个方法。AbstractAutoProxyCreator 和 AbstractAdvisingBeanPostProcessor 这个 postProcessAfterInitialization 方法都会返回一个代理对象(Proxy)。

添加到三级缓存中的代码:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    private final Map<String, Object> earlySingletonObjects = new HashMap(16);
    // 添加到三级缓存的方法
   protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
      Assert.notNull(singletonFactory, "Singleton factory must not be null");
      synchronized (this.singletonObjects) {
         if (!this.singletonObjects.containsKey(beanName)) {
             this.singletonFactories.put(beanName, singletonFactory);
             this.earlySingletonObjects.remove(beanName);
             this.registeredSingletons.add(beanName);
         }
      }
  }
}

AbstractAutowireCapableBeanFactory 类的 doCreateBean 方法中,调用添加三级缓存方法的部分:

if (earlySingletonExposure) {
       //......
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
 }

所以缓存的 ObjectFactory 对象是由一个lamda表达式获得的,真正获取 三级缓存 ObjectFactory 对象的方法是 getEarlyBeanReference。

AbstractAutowireCapableBeanFactory 类的 getEarlyBeanReference 方法:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
               SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
               exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
       }
    }
    return exposedObject;
}

如果实现了 SmartInstantiationAwareBeanPostProcessor 接口,会调用实现的 SmartInstantiationAwareBeanPostProcessor 接口的 getEarlyBeanReference 方法获取三级缓存 ObjectFactory 对象。

而前面提到的 AnnotationAwareAspectJAutoProxyCreator 这个类就实现了 SmartInstantiationAwareBeanPostProcessor 接口,有 getEarlyBeanReference (早期暴露引用对象)方法为:

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
  @Override
  public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
          this.earlyProxyReferences.add(cacheKey);
      }
      return wrapIfNecessary(bean, beanName, cacheKey);
  }
}

这个方法最后会调用 wrapIfNecessary 方法,前面也说过,这个方法是获取动态代理的方法,如果需要的话就会代理,比如事务注解又或者是自定义的AOP切面,在早期暴露的时候,就会完成动态代理。

为什么 @Async 注解遇上循环依赖,Spring 无法解决?

AService加了@Async注解,AService先创建,发现引用了BService,那么BService就会去创建,当Service创建的过程中发现引用了AService,那么就会通过AnnotationAwareAspectJAutoProxyCreator 这个类实现的 getEarlyBeanReference 方法获取AService的早期引用对象,此时这个早期引用对象可能会被代理,取决于AService是否需要被代理,但是一定不是处理@Async注解的代理,原因前面也说过。

于是 BService 创建好之后(已经是代理对象),注入给了AService,那么AService 初始化阶段完成之后继续往下处理,会调用所有的BeanPostProcessor的实现的 postProcessAfterInitialization 方法。于是就会依次回调 AnnotationAwareAspectJAutoProxyCreator 和 AsyncAnnotationBeanPostProcessor 的 postProcessAfterInitialization 方法实现。

这段回调有两个细节:

  • AnnotationAwareAspectJAutoProxyCreator 先执行,AsyncAnnotationBeanPostProcessor 后执行,因为 AnnotationAwareAspectJAutoProxyCreator 在前面。
  • AnnotationAwareAspectJAutoProxyCreator 处理后会继续交给 AsyncAnnotationBeanPostProcessor 处理,applyBeanPostProcessorsAfterInitialization方法就是这么实现的

最后的结果:

  • AnnotationAwareAspectJAutoProxyCreator回调:会发现 AService 对象已经被早期引用了,什么都不处理,直接把对象AService给返回
  • AsyncAnnotationBeanPostProcessor回调:发现AService类中加了@Async注解,那么就会对AnnotationAwareAspectJAutoProxyCreator返回的对象进行动态代理,然后返回了动态代理对象。早期暴露出去的对象,可能是AService本身或者是AService的代理对象,而且是通过AnnotationAwareAspectJAutoProxyCreator对象实现的,但是通过AsyncAnnotationBeanPostProcessor的回调,会对AService对象进行动态代理,这就导致AService早期暴露出去的对象跟最后完全创造出来的对象不是同一个,那么肯定就不对了。同一个Bean在一个Spring中怎么能存在两个不同的对象呢,于是就会抛出BeanCurrentlyInCreationException异常。

 

2、constructor 注入的循环依赖

 A --> B --> A,且 都是通过构造函数依赖

@Service
public class A {
    private B b;
    
    public A(B b) {
        this.b=b;
    }
}
 
@Service
public class B {
    private A a;
    
    public B(A a) {
        this.a=a;
    }
}
  • A 实例在创建时(createBeanInstance),由于是构造注入,这时会触发 B 的加载。
  • B 实例在创建时(createBeanInstance),又会触发 A 的加载,此时,A 还没有添加到三级缓存中(A 实例还在调构造方法,还没创建成功),所以就会创建一个全新的 A。

这样,就会进入一个死循环。Spring 是解决不了这种情况下的循环依赖的。所以,提前进行了 check,并抛出了异常。

 

出现循环依赖异常之后如何解决?

可以在循环依赖注入的字段上加@Lazy注解

@Component
public class AService {
    @Resource
    @Lazy
    private BService bService;
 
    @Async
    public void save() {
 
    }
}
public A(@Lazy B b){
    System.out.println("A的构造方法执行了...");
    this.b = b ;
}

@Lazy注解只对单例有用,对原型没有用。

当使用 @Lazy 注解时,Spring Boot会将Bean对象的初始化推迟到第一次使用时才进行。这样,当两个或多个Bean对象存在循环依赖时,其中一个Bean对象在初始化时可以直接引用另一个Bean对象的代理对象(未初始化的对象),而不需要等待另一个Bean对象完全初始化后再进行引用。