什么是Bean

Bean是在Spring中对于对象的描述,原因是每一个实例对象都可以通过xml配置文件中的bean标签来创建,由beans标签来管理所有的bean对象,因此也说Spring是管理bean的容器。

通过学习IOC初始化流程,我们知道Spring通过加载解析资源配置文件,生成BeanDefinition并注册到IOC容器中。容器中存放的是Bean的定义(BeanDefinition存放到beanDefinitionMap中),IOC容器本质上是一个ConcurrentHashMap集合,并且BeanDefinition接口中包含了这个类的Class信息以及是否是单例等信息(即一些行为信息)

在这里插入图片描述

红框部分就是getBean

1. BeanFactory中如何getBean

通过的学习,我们知道,BeanFactory定义了Bean容器的规范,其中包括根据bean的名字、Class类型和参数等来得到Bean的实例

//根据bean的名字和Class类型等来得到bean实例    
Object getBean(String name) throws BeansException;    
Object getBean(String name, Class requiredType) throws BeansException;    
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

BeanFactory实现getBean的主体思路:

  • 从beanDefinitionMap中通过beanName获得BeanDefinition

  • 从BeanDefinition中获得beanClassName

  • 通过反射初始化beanClassName的实例instance

    • 构造函数从BeanDefinition的getConstructorArgumentValues()方法获取

    • 属性值从BeanDefinition的getPropertyValues()方法获取

  • 返回beanName的实例instance

由于BeanDefinition还有单例的信息,如果是无参构造函数的实例还可以放在一个缓存中,这样下次获取这个单例的实例时只需要从缓存中获取,如果获取不到再通过上述步骤获取

源码解析

BeanFactory的getBean方法实现在AbstractBeanFactory中,这个方法重载都是调用doGetBean方法进行实现的

public Object getBean(String name) throws BeansException {
  return this.doGetBean(name, (Class)null, (Object[])null, false);
}

public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
  return this.doGetBean(name, requiredType, (Object[])null, false);
}

public Object getBean(String name, Object... args) throws BeansException {
  return this.doGetBean(name, (Class)null, args, false);
}

public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException {
  return this.doGetBean(name, requiredType, args, false);
}

核心的实现就是doGetBean方法

/**
  * typeCheckOnly:bean实例是否包含一个类型检查
 **/
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
  //解析Bean的真正name,如果bean是工厂类,name前缀会加&,需要去掉
  String beanName = this.transformedBeanName(name);
  //快速检查单例Bean对象缓存是否存在
  Object sharedInstance = this.getSingleton(beanName);
  Object bean;
  //如果获取不到Bean对象的单例缓存
  if (sharedInstance != null && args == null) {
    //是否启用了日志跟踪(启用日志跟踪则会跟踪单例Bean的创建进度)
    if (this.logger.isTraceEnabled()) {
      //单例Bean是否正在创建中
      if (this.isSingletonCurrentlyInCreation(beanName)) {
        this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
      } else {
        this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
      }
    }
    //获取单例bean的实例,并放入缓存
    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
  } else {
    //如果bean实例还在创建中,则直接抛出异常
    if (this.isPrototypeCurrentlyInCreation(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
    }
    //如果beanDefinition存在于父Bean工厂中,则委派给父BeanFactory工厂来获取
    BeanFactory parentBeanFactory = this.getParentBeanFactory();
    if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
      String nameToLookup = this.originalBeanName(name);
      if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
      }

      if (args != null) {
        //委派给具有明确参数的父类
        return parentBeanFactory.getBean(nameToLookup, args);
      }

      if (requiredType != null) {
        //没有参数->委派给标准的getBean
        return parentBeanFactory.getBean(nameToLookup, requiredType);
      }

      return parentBeanFactory.getBean(nameToLookup);
    }

    if (!typeCheckOnly) {
      //将当前的Bean实例放入alreadyCreated集合里,标识这个bean准备创建了
      this.markBeanAsCreated(beanName);
    }

    try {
      RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
      this.checkMergedBeanDefinition(mbd, beanName, args);
      
      //确保它的依赖也被初始化
      String[] dependsOn = mbd.getDependsOn();
      String[] var11;
      if (dependsOn != null) {
        var11 = dependsOn;
        int var12 = dependsOn.length;

        for(int var13 = 0; var13 < var12; ++var13) {
          String dep = var11[var13];
          if (this.isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
          }

          this.registerDependentBean(dep, beanName);

          try {
            //初始化它依赖的Bean
            this.getBean(dep);
          } catch (NoSuchBeanDefinitionException var24) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);
          }
        }
      }
      //创建Bean实例:单例
      if (mbd.isSingleton()) {
        sharedInstance = this.getSingleton(beanName, () -> {
          try {
            //真正创建bean的方法
            return this.createBean(beanName, mbd, args);
          } catch (BeansException var5) {
            //如果出现异常要销毁当前创建的单例bean实例
            this.destroySingleton(beanName);
            throw var5;
          }
        });
        bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        //创建bean实例:原型
      } else if (mbd.isPrototype()) {
        var11 = null;

        Object prototypeInstance;
        try {
          this.beforePrototypeCreation(beanName);
          prototypeInstance = this.createBean(beanName, mbd, args);
        } finally {
          this.afterPrototypeCreation(beanName);
        }

        bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
        //创建bean实例:根据bean的scope创建
      } else {
        String scopeName = mbd.getScope();
        if (!StringUtils.hasLength(scopeName)) {
          throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
        }

        Scope 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, () -> {
            this.beforePrototypeCreation(beanName);

            Object var4;
            try {
              var4 = this.createBean(beanName, mbd, args);
            } finally {
              this.afterPrototypeCreation(beanName);
            }

            return var4;
          });
          bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
        } catch (IllegalStateException var23) {
          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", var23);
        }
      }
    } catch (BeansException var26) {
      this.cleanupAfterBeanCreationFailure(beanName);
      throw var26;
    }
  }
  //Bean实例的类类型是否和指定转换的类类型相同
  if (requiredType != null && !requiredType.isInstance(bean)) {
    try {
      //将bean的类型转换为传入的class类型
      T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
      if (convertedBean == null) {
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      } else {
        return convertedBean;
      }
    } catch (TypeMismatchException var25) {
      if (this.logger.isTraceEnabled()) {
        this.logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var25);
      }

      throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    }
  } else {
    return bean;
  }
}

源码解析:

  • 解析bean的真正name,如果bean是工厂类,name前缀会加&,需要去掉

  • 无参单例先从缓存中尝试获取

  • 如果bean实例还在创建中,则直接抛出异常

  • 如果beanDefinition存在于父的bean工厂中,委派给父bean工厂获取

  • 标记这个beanName的实例正在创建

  • 确保它的依赖也被初始化

  • 真正创建的

    • 单例时

    • 原型时

    • 根据bean的scope创建

2. Spring的两种bean类型

BeanFactory中FACTORY_BEAN_PREFIX用于区分两种Bean类型

//用于取消引用实例并将其与FactoryBean创建的bean区分开来。例如,如果命名的bean是FactoryBean,则获取将返回Factory,而不是Factory返回的实例。
String FACTORY_BEAN_PREFIX = "&";

2.1 普通bean

class Dept {
    private String dName;

    public void setdName(String dName) {
        this.dName = dName;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "dName='" + dName + '\'' +
                '}';
    }
}
<bean id="dept" class="com.carl.entity.Emp.Dept">
    <property name="dName" value="研发部"/>
</bean>
@Test
public void testDeptAndEmp(){
    ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
    Dept dept= context.getBean("dept", Dept.class);
    System.out.println(dept);
}

特点:定义什么bean,返回什么类型的bean

2.2 工厂bean(FactoryBean)

public class User {
    private String id;
    private String name;
    private Integer age;
    private String sex;

    public User(String id, String name, Integer age, String sex) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
public class MyBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        //这才是实际获取的对象
        User user=new User("2", "徐总", 20, "女");
        return user;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}
<bean id="myBean" class="com.carl.factoryBean.MyBean"/>
@Test
public void testFactoryBean(){
    ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
    User user = context.getBean("myBean", User.class);
    System.out.println(user);
}

3. Bean的作用域

在Spring里面,可以设置创建的bean实例是单例还是多例,在默认情况下,bean实例是一个单例对象

说明:在bean标签中有一个属性(scope)

有两个值:singleton和prototype可以定义该实例的创建方式为单例还是多例,默认是singleton

两个值的区别:

  • singleton:表示该对象的创建模式为单例模式(全局),且在解析xml文件时创建对象实例

  • prototype:表示该对象的创建模式为多例模式(当前使用范围),且在调用getBean()方法时创建对象实例

<bean id="myBean" class="com.carl.factoryBean.MyBean"/>
@Test
public void testFactoryBean(){
    ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
    User user1 = context.getBean("myBean", User.class);
    User user2 = context.getBean("myBean", User.class);
    System.out.println(user1);
    System.out.println(user2);
}
com.carl.entity.User@e720b71
com.carl.entity.User@e720b71
<bean id="myBean" class="com.carl.factoryBean.MyBean" scope="prototype"/>
@Test
public void testFactoryBean(){
    ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
    User user1 = context.getBean("myBean", User.class);
    User user2 = context.getBean("myBean", User.class);
    System.out.println(user1);
    System.out.println(user2);
}
com.carl.entity.User@4d3167f4
com.carl.entity.User@ed9d034

4. Bean的生命周期

Spring只帮我们管理单例模式的Bean的完整生命周期,对于prototype(原型)的bean,Spring在创建好交给使用者之后则不会再管理后续的生命周期

Spring容器可以管理singleton作用域Bean的生命周期,在此作用域下,Spring能够精确的知道该Bean何时被创建,何时初始化,以及何时被销毁

对于prototype作用域的Bean,Spring只是负责创建,当容器创建了Bean的实例之后,Bean的实例就交给了客户端代码管理,Spring容器将不再跟踪其生命周期。每次客户端请求prototype作用域的Bean时,Spring容器都会创建一个新的实例,并且不会管理那些被配置成prototype作用域的Bean的生命周期

了解Spring Bean的生命周期,可以利用Bean在其存活期间的指定时刻完成一些相关操作,这种时刻可能有很多,但一般情况下,会在Bean被初始化后或被销毁之前执行一些相关操作

在这里插入图片描述

Spring容器中Bean的生命周期流程

如图所示:

  • 如果BeanFactoryPostProcessor和Bean关联,则调用postProcessBeanFactory方法(首先尝试从Bean工厂中获取Bean)

  • 如果InstantiationAwareBeanPostProcessor和Bean关联,则调用postProcessBeforeInstantiation方法

  • 根据配置情况调用Bean构造方法实例化Bean

  • 利用依赖注入完成Bean中所有属性值的配置注入

  • 如果InstantiationAwareBeanPostProcessor和Bean关联,则调用postProcessAfterInstantiation方法和postProcessProperties

  • 调用xxxAware接口

    • 第一类Aware接口

      • 如果Bean实现了BeanNameAware接口,则Spring调用Bean的setBeanName()方法传入当前Bean的id值

      • 如果Bean实现了BeanClassLoaderAware接口,则Spring调用setBeanClassLoader()方法传入classLoader的引用

      • 如果Bean实现了BeanFactoryAware接口,则Spring调用setBeanFactory()方法传入当前工厂实例的引用

    • 第二类Aware接口

      • 如果Bean实现了EnvironmentAware接口,则Spring调用setEnvironment()方法传入当前Environment实例的引用

      • 如果Bean实现了EmbeddedValueResolverAware接口,则Spring调用setEmbeddedValueResolver()方法传入当前StringValueResolver实例的引用

      • 如果Bean实现了ApplicationContextAware接口,则Spring调用setApplicationContext()方法传入当前ApplicationContext实例的引用

  • 如果BeanPostProcessor和Bean关联,则Spring将调用该接口的预初始化方法postProcessBeforeInitialzation()对Bean进行加工操作,Spring的AOP就是利用它实现的

  • 如果Bean实现了InitializingBean接口,则Spring将调用afterPropertiesSet()方法,或者有执行@PostConstruct注解的方法

  • 如果在配置文件中通过init-method属性指定了初始化方法,则调用该初始化方法

  • 如果BeanPostProcessor和Bean关联,则Spring将调用该接口的初始化postProcessAfterInitialization()。此时Bean已经可以被应用系统使用了

  • 如果在<bean>中指定了该bean的作用范围为scope="singleton",则将该Bean放入SpringIOC的缓存池中,将触发Spring对该Bean的生命周期管理;如果在<bean>中指定了该Bean的作用范围为scope="prototype",则Spring将该Bean交给调用者,调用者管理该Bean的生命周期,Spring将不再管理该Bean

  • 如果Bean实现了DisposableBean接口,则Spring会调用destory()方法将Spring中的Bean销毁;或者有执行@PreDestory注解的方法

  • 如果在配置文件中通过destory-method属性指定了Bean的销毁方法,则Spring将调用该方法对Bean进行销毁

Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

  • Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中<bean>init-methoddestory-method指定的方法

  • Bean级生命周期接口方法:这个包括了BeanNameAwareBeanFactoryAwareApplicationContextAware;当然还包括initializingBeanDiposableBean这些接口的方法,可以被@PostConstruct@PreDestory注解替代

  • 容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessorBeanPostProcessor这两个接口实现,一般称它们的实现类为"后处理器"

  • 工厂后处理器接口方法:这个包括AspectJWeavingEnablerConfigurationClassPostProcessorCustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法,工厂后处理器也是容器级的,在应用上下文装配配置文件之后立即调用

Bean自身的方法

  1. 通过无参构造器创建bean实例(有参构造器也可以创建bean的实例并注入属性)

  2. 为bean的属性注入值和对其他bean的注入(调用set方法、有参构造器、接口等方式)

  3. 调用bean的初始化方法(需要配置初始化的方法)

    public void initMethod(){
        System.out.println("初始化方法");
    }
    
    <bean id="student" class="com.carl.entity.Student" init-method="initMethod">
        <property name="stuName" value="张三"/>
        <property name="stuCourse" value="Python"/>
    </bean>
    
  4. 使用bean实例(获取bean实例对象并使用)

  5. 当容器关闭时,调用bean的销毁方法(需要配置销毁的方法)

    public void destroyMethod(){
        System.out.println("销毁方法");
    }
    
    <bean id="student" class="com.carl.entity.Student" init-method="initMethod" destroy-method="destroyMethod">
            <property name="stuName" value="张三"/>
            <property name="stuCourse" value="Python"/>
        </bean>
    
    @Test
    public void testCycleBean(){
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
        Student student = context.getBean("student", Student.class);
        System.out.println(student);
        //在没有启动Spring的时候,必须手动执行销毁bean的方法
        //ApplicationContext对象中是没有close方法的,必须强制转换为ClassPathXmlApplicationContext或直接获取ClassPathXmlApplicationContext对象
        context.close();
    }
    

Bean的生命周期接口方法

import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * @author 杰尼龟的小龟壳
 */
@Slf4j
@ToString
public class User implements BeanFactoryAware, BeanNameAware, ApplicationContextAware,
        InitializingBean, DisposableBean {
    /**
     * user's name.
     */
    private String name;

    /**
     * user's age.
     */
    private int age;

    /**
     * bean factory.
     */
    private BeanFactory beanFactory;

    /**
     * application context.
     */
    private ApplicationContext applicationContext;

    /**
     * bean name.
     */
    private String beanName;

    public User() {
        log.info("execute User#new User()");
    }

    public void setName(String name) {
        log.info("execute User#setName({})", name);
        this.name = name;
    }

    public void setAge(int age) {
        log.info("execute User#setAge({})", age);
        this.age = age;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("execute BeanFactoryAware#setBeanFactory");
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String s) {
        log.info("execute BeanNameAware#setBeanName");
        this.beanName = s;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("execute ApplicationContextAware#setApplicationContext");
        this.applicationContext = applicationContext;
    }

    @Override
    public void destroy() throws Exception {
        log.info("execute DisposableBean#destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("execute InitializingBean#afterPropertiesSet");
    }


    public void doInit() {
        log.info("execute User#doInit");
    }

    public void doDestroy() {
        log.info("execute User#doDestroy");
    }

}
/**
 * @author 杰尼龟的小龟壳
 */
@Slf4j
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        log.info("execute BeanFactoryPostProcessor#postProcessBeanFactory");
    }
}
/**
 * @author 杰尼龟的小龟壳
 */
@Slf4j
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        log.info("execute InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation for {}", beanName);
        return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        log.info("execute InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation for {}", beanName);
        return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        log.info("execute InstantiationAwareBeanPostProcessor#postProcessProperties for {}", beanName);
        return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
    }
}
@Slf4j
public class App {

    /**
     * main interface.
     *
     * @param args args
     */
    public static void main(String[] args) {
        log.info("Init application context");
        // create and configure beans
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                "tech.pdai.springframework");

        // retrieve configured instance
        User user = (User) context.getBean("user");

        // print info from beans
        log.info(user.toString());

        log.info("Shutdown application context");
        context.registerShutdownHook();
    }
}
12:44:42.547 [main] INFO com.carl.springframework.App - Init application context
...
12:44:43.134 [main] INFO com.carl.springframework.processor.MyBeanFactoryPostProcessor - execute BeanFactoryPostProcessor#postProcessBeanFactory
...
12:44:43.216 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
12:44:43.216 [main] INFO com.carl.springframework.processor.MyInstantiationAwareBeanPostProcessor - execute InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation for user
12:44:43.236 [main] INFO com.carl.springframework.entity.User - execute User#new User()
12:44:43.237 [main] INFO com.carl.springframework.entity.User - execute User#setName(pdai)
12:44:43.237 [main] INFO com.carl.springframework.entity.User - execute User#setAge(18)
12:44:43.237 [main] INFO com.carl.springframework.processor.MyInstantiationAwareBeanPostProcessor - execute InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation for user
12:44:43.237 [main] INFO com.carl.springframework.processor.MyInstantiationAwareBeanPostProcessor - execute InstantiationAwareBeanPostProcessor#postProcessProperties for user
12:44:43.242 [main] INFO com.carl.springframework.entity.User - execute BeanNameAware#setBeanName
12:44:43.242 [main] INFO com.carl.springframework.entity.User - execute BeanFactoryAware#setBeanFactory
12:44:43.242 [main] INFO com.carl.springframework.entity.User - execute ApplicationContextAware#setApplicationContext
12:44:43.242 [main] INFO com.carl.springframework.entity.User - execute InitializingBean#afterPropertiesSet
12:44:43.270 [main] INFO com.carl.springframework.App - User(name=pdai, age=18)
12:44:43.270 [main] INFO com.carl.springframework.App - Shutdown application context
12:44:43.276 [SpringContextShutdownHook] INFO com.carl.springframework.entity.User - execute DisposableBean#destroy

bean的后置处理器

bean后置处理器(BeanPostProcessor)是一种特殊的bean,并不对外提供服务,甚至无需使用id属性

package com.carl.entity.post;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @PackageName com.carl.entity.post
 * @Auther carl
 * @Description: 后置处理器
 * @Version V1.0
 * @Date 2022-09-26 22:09
 * Modified By:TODO
 **/
public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后置处理器Before-Method");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后置处理器After-Method");
        return bean;
    }
}
<!--配置后置处理器:为当前配置文件中的所有bean添加后置处理器,可以不用配置id属性-->
<bean id="myBeanPost" class="com.carl.entity.post.MyBeanPost"/>

加上bean的后置处理器后的生命周期

  1. 通过无参构造器创建bean实例(有参构造器也可以创建bean的实例并注入属性)

  2. 为bean的属性注入值和对其他bean的注入(调用set方法、有参构造器、接口等方式)

  3. 把bean实例传递给bean后置处理器的postProcessBeforeInitialization方法

  4. 调用bean的初始化方法(需要配置初始化的方法)

  5. 把bean实例传递给bean后置处理器的postProcessAfterInitialization方法

  6. 使用bean实例(获取bean实例对象并使用)

  7. 当容器关闭时,调用bean的销毁方法(需要配置销毁的方法)

@Test
public void testPostBean(){
    ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
    Student student = context.getBean("student", Student.class);
    System.out.println(student);
    //手动销毁bean
    context.close();
}
后置处理器Before-Method
初始化方法
后置处理器After-Method
com.carl.entity.Student@1990a65e
销毁方法

初始化自定义操作可以通过两种方式来实现

  • 接口的方式

    Spring提供了InitializingBean接口,实现afterPropertiesSet()方法即可在bean实例创建后实现初始化时的其他操作

    @Component
    public class User implements InitializingBean {
        /**
         * @see String
         * 姓名
         */
        private String name;
        public Integer add(int a,int b){
            int i = a / b;
            System.out.println("User Add Result:"+a / b);
            return i;
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("初始化afterPropertiesSet");
        }
    }
    
  • xml配置方式

    <bean id="user" class="com.carl.entity.User" init-method="init">
        <property name="name" value="张三"/>
    </bean>
    
    public class User{
        /**
         * @see String
         * 姓名
         */
        private String name;
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer add(int a, int b){
            int i = a / b;
            System.out.println("User Add Result:"+a / b);
            return i;
        }
    
        public void init() throws Exception {
            System.out.println("初始化init");
        }
    }
    

这两种初始化操作的方式,在后置处理器中的执行顺序如下

在这里插入图片描述

容器的后置处理器

容器的后置处理器必须实现BeanFactoryPostProcessor

package com.carl.entity.post;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;


/**
 * @Version 1.0.0
 * @see BeanFactoryPostProcessor
 * @author carl蔡先生
 * @Date 2022/10/06
 * @Description 自定义容器后置处理器
 */
public class MyBeanFactoryPost implements BeanFactoryPostProcessor {
    /**
     * 后处理bean工厂
     * @param configurableListableBeanFactory 可配置列表bean工厂
     * @throws BeansException beans异常
     *
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("Spring后置处理器");
    }
}
<!--如果使用自动扫描机制,则这个可以不用配置-->
<bean id="myBeanFactoryPost" class="com.carl.entity.post.MyBeanFactoryPost"/>

5. Bean的循环依赖问题

Spring只是解决了单例模式下属性依赖的循环问题,为了解决这个问题,Spring使用了三级缓存

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
 
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
  • 第一层缓存(singletonObjects):单例对象缓存池,已经实例化并且数据赋值,这里的对象是成熟的对象

  • 第二层缓存(earlySingletonObjects):单例对象缓存池,已经实例化但尚未属性赋值,这里的对象是半成品对象

  • 第三层缓存(singletonFactories):单例工厂的缓存

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  //Spring首先从singletonObjects中尝试获取
  Object singletonObject = this.singletonObjects.get(beanName);
  //如果获取不到,且对象在建立中,则尝试从earlySingletonObjects中获取
  if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
    singletonObject = this.earlySingletonObjects.get(beanName);
    //如果获取不到,且允许提前从singletonFactories中经过getObject拿到对象
    if (singletonObject == null && allowEarlyReference) {
      synchronized(this.singletonObjects) {
        singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
          singletonObject = this.earlySingletonObjects.get(beanName);
          if (singletonObject == null) {
            //获取singletonFactory工厂对象
            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
              //如果以及缓存和二级缓存依旧获取不到,且允许从singletonFactories经过getObject获取,则经过singletonFactory.getObject()获取
              singletonObject = singletonFactory.getObject();
              //如果获取到了三级缓存,则将singletonObject存入earlySingletonObjects,即:将三级缓存提升到二级缓存中
              this.earlySingletonObjects.put(beanName, singletonObject);
              //三级缓存中的数据会删除
              this.singletonFactories.remove(beanName);
            }
          }
        }
      }
    }
  }

  return singletonObject;
}

isSingletonCurrentlyInCreation():判断当前单例Bean是否正在建立中,也就是没有初始化完成(例如:A的构造器依赖了B对象,因此得先去建立B对象;或者在A的populateBean过程中依赖了B对象,得先去建立B对象,这时的A就是处于建立中的状态)

allowEarlyReference:是否允许从singletonFactories中经过getObject拿到对象

分析获取单例的源码:

  1. Spring首先从一级缓存singletonObjects中获取

  2. 如果获取不到,且对象正在建立中,就从二级缓存earlySingletonObjects中获取

  3. 如果仍然获取不到,且允许singletonFactories经过getObject()获取,就从三级缓存singletonFactory.getObject()中获取

  4. 如果获取到了,则需要将三级缓存移动到二级缓存中

public interface ObjectFactory<T> {
    T getObject() throws BeansException;
}
//在bean建立过程中,有两处比较重要的匿名内部类实现了该接口:一处是Spring利用其建立bean的时候,另一处就是下面这段代码
addSingletonFactory(beanName, new ObjectFactory<Object>() {
   @Override   public Object getObject() throws BeansException {
      return getEarlyBeanReference(beanName, mbd, bean);
   }});

此代码就是解决循环依赖的关键

addSingletonFactory发生在createBeanInstance之后,即单例对象此时已经被建立出来了,虽然还未进行初始化的第二步和第三步,但是已经能根据对象的引用定位到堆中的对象,因此Spring就将这个对象提早获取并使用

例如:A对象的setter依赖B对象,B对象setter依赖A对象

  1. A首先完成了初始化的第一步,而且将本身提早添加到singletonFactories中

  2. 此时A对象进行初始化的第二步,发现本身依赖对象B

  3. 然后就开始尝试去get(B),发现B还没有被创建,就开始走B对象的创建流程

  4. B在初始化过程中发现本身依赖了对象A,因此尝试get(A),尝试一级缓存singletonObjects没有找到A(因为A没有完全初始化)、尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存(因为A对象已经在singletonFactories添加了,所以获取到半初始化的A对象)

  5. B对象拿到A对象后就能够顺利进行初始化一、二、三阶段,彻底初始化后将本身放入一级缓存singletonObjects中

  6. 返回初始化A的流程,A拿到B的对象顺利完成本身的初始化一、二、三阶段,彻底初始化后将本身放入一级缓存singletonObjects中

Spring为什么不解决单例之外的循环依赖

Spring为什么不能解决构造器的循环依赖

构造器注入形成的循环依赖:也就是B对象需要在A对象的构造函数中完成初始化,A也需要在B对象的构造器中完成初始化,这种情况的结果就是两个Bean都不能完成初始化

Spring解决循环依赖主要是依赖三级缓存,但是在调用构造方法之前,还未将其放入三级缓存中,因此后续的依赖调用构造器的时候并不能从三级缓存中获取到依赖的bean,因此不能解决

Spring为什么不能解决prototype作用域循环依赖

这种循环依赖同样无法解决,因为Spring不会缓存prototype作用域的bean,而Spring中循环依赖的解决正是通过缓存来实现的

Spring为什么不能解决多例的循环依赖

多实例Bean的每次调用一次getBean都会执行一次构造方法并且给属性赋值,根本没有三级缓存,因此也不能解决循环依赖

这些循环依赖问题如何解决
  • 生成代理对象产生的循环依赖

    解决这类循环依赖问题方法如下:

    • 使用@Lazy注解延迟加载

    • 使用@DependsOn注解指定加载的先后关系

    • 修改文件名称,改变循环依赖类的加载顺序

  • 使用@DependsOn产生的循环依赖

    这类循环依赖问题要找到@DependsOn注解循环依赖的地方,迫使它不循环依赖就可以解决问题

  • 多例循环依赖

    这类循环依赖问题,可以通过把Bean改成单例的解决

  • 构造器循环依赖

    这类循环问题可以通过使用@Lazy注解解决

什么是Bean管理

  • 创建对象

  • 注入属性:这里的属性是类的属性

  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Carl·杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值