Spring's Bean life cycle source code analysis (2)

Spring's Bean life cycle source code analysis (2)

  • review
  • Before instantiation
  • instantiate
  • Inferred constructor
  • Postprocessing of BeanDefinition
  • after instantiation
  • automatic injection
  • fill attribute
  • Execute the Aware callback interface
  • Before initialization
  • initialization
  • after initialization
  • Summarize BeanPostProcessor

review

Bean life cycle flow chart

Bean life cycle.png

Packet Scanning Flowchart

Spring package scans the underlying process.png

Before instantiation

After the class corresponding to the current BeanDefinition is successfully loaded, the object can be instantiated.

But in Spring, before instantiating an object, Spring provides an extension point that allows users to control whether to do some startup actions before a certain bean or certain beans are instantiated.

This extension point is called InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()

It should be noted that there is a return value here. If this is implemented and an object is returned, then the subsequent Spring dependency injection will not be performed, and some steps will be skipped and the step after initialization will be performed directly.

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    @Nullable
  default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    return null;
  }
  ...
}  
复制代码

instantiate

In this step, an object will be created according to the BeanDefinition.

Supplier creates object

First determine whether the BeanDefinition has set Supplier, and if it is set, it will call Supplier#get() to get the object.

@Test
  public void testSupplier() {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
    bd.setInstanceSupplier(UserService::new);
    ctx.registerBeanDefinition("userService", bd);
    UserService userService = ctx.getBean("userService", UserService.class);
    userService.test();
  }
复制代码

Factory method to create object

If Supplier is not set, it will check whether the BeanDefinition has factoryMethod set, which is the factory method. There are two ways to set factoryMethod

method one

<bean id="userService" class="linc.cool.service.UserService" factory-method="createMethod" />
复制代码

corresponding class

public class UserService{

  public void test() {
    System.out.println(this.getClass().getName() + ".test()");
  }


  public static UserService createMethod() {
    System.out.println("执行createUserService()");
    return new UserService();
  }
}

复制代码

Method 2

  <bean id="commonService" class="linc.cool.service.CommonService"/>
  <bean id="userService" factory-bean="commonService" factory-method="createUserService"/>
复制代码

Corresponding CommonService

public class CommonService {
  public UserService createUserService() {
    return new UserService();
  }
}
复制代码

After Spring finds that the factory method is set in the current BeanDefinition method, it will distinguish between these two methods, and then call the factory method to get the object

Note that the BeanDefinition we define through @Bean has factoryMethod and factoryBean, which is very similar to the second method above.

The method annotated by @Bean is factoryMethod, and the AppConfig object is factoryBean

If the method annotated by @Bean is static, then the corresponding method is one

Inferred constructor

Spring在基于某个类生成Bean的过程中,需要利用该类的构造方法来实例化得到一个对象,但是如果一个类中存在多个构造方法,Spring的判断逻辑如下:

  • 如果一个类只存在一个构造方法,不管这个构造方法是无参构造还是有参构造方法,Spring都会使用这个构造方法

  • 如果一个类中存在多个构造方法

    • 这些构造方法中,存在一个无参构造方法,那么Spring就会使用这个无参构造方法
    • 这些构造方法中,不存在无参构造方法,那么Spring就会报错
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [linc.cool.service.UserService]: No default constructor found; nested exception is java.lang.NoSuchMethodException: linc.cool.service.UserService.<init>()
复制代码

Spring的设计思想是这样的

  1. 如果一个类只有一个构造方法,那么没得选择,只能用这个构造方法

  2. 如果一个类存在多个构造方法,Spring不知道如何选择,就会看是否有无参构造方法,因为无参构造方法本身表示了一种默认的意义

  3. 如果某个构造方法上加了@Autowired注解,那就表示程序员告诉Spring我采用这个构造方法进行构造,如果Spring选择了一个有参的构造方法,Spring在调用这个有参构造方法时,需要传入参数,这些参数是怎么来的呢?

    Spring会根据入参的类型和入参的名字去Spring中找Bean对象,我们以单例为例,Spring会从单例池sigletonObjects中去找:

    • 先根据入参类型找,如果只找到一个,那么久直接用来作为入参
    • 如果根据入参类型找到多个,就会再去根据入参名字去确定唯一的一个
    • 最终如果没有找到就会报错,无法创建当前Bean对象

额外的,在推断构造方法逻辑中除开回去选择构造方法以及查找入参对象以外,还会去判断是否存在对应的类中是否存在使用@Lookup注解了的方法.

如果存在就会把这个方法封装为LookupOverride对象并且添加到BeanDefinition

public class LookupOverride extends MethodOverride {
  @Nullable
  private final String beanName;
  
  @Nullable
  private Method method;
  ...
}
复制代码

@Lookup注解就是方法注入

@Component
public class AService {
  private BService bService;

  public void test() {
    BService bService = createBService();
    System.out.println(bService);
    System.out.println(this.getClass().getName() + ".test()");
  }

  @Lookup
  public BService createBService() {
    return new BService();
  }

}
复制代码

BeanDefinition的后置处理

Bean对象实例化出来之后,接下来就应该给对象的属性进行赋值了

在真正给属性赋值之前,Spring又提供了一个扩展点MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition,可以对此事的BeanDefinition进行加工

在Spring源码中,AutowiredAnnotationBeanPostProcessor就是一个MergedBeanDefinitionPostProcessor,它的postProcessMergedBeanDefinition中会去查找注入点,并缓存在AutowiredAnnotationBeanPostProcessor对象的一个Map中(injectionMetadataCache)

@Component
public class AMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
  @Override
  public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    if ("AService".equals(beanName)) {
      beanDefinition.getPropertyValues().add("BService", new BService());
    }
  }
}
复制代码
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
    MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
      ...
     private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
      ...
}      
复制代码

实例化后

在处理完BeanDefinition之后,Spring又设计了一个扩展点InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    @Nullable
  default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    return true;
  }
  ...
}  
复制代码

自动注入

自动注入指的是Spring的自动注入

填充属性

在这个步骤中,就会处理@Autowired、@Resource、@Value等注解

也就是通过InstantiationAwareBeanPostProcessor#postProcessProperties扩展点来实现的

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
  @Nullable
  default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
      throws BeansException {

    return null;
  }
  ...
}  
复制代码

我们可以自己实现一个注入点

@Component
public class MyAutowiredInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
  @Override
  public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    if ("AService".equals(beanName)) {
      Stream.of(bean.getClass().getDeclaredFields()).forEach(f -> {
        if (f.isAnnotationPresent(MyAutowired.class)) {
          String value = f.getAnnotation(MyAutowired.class).value();
          f.setAccessible(true);
          try {
            f.set(bean, value);
          } catch (IllegalAccessException e) {
            e.printStackTrace();
          }
        }
      });
    }
    return pvs;
  }
}
复制代码

后续涉及到的有@Autowired、@Resource、@Value的底层源码

执行Aware回调接口

完成了属性赋值之后,Spring会执行一些回调接口

  • BeanNameAware: 回传beanName给bean对象
  • BeanClassLoaderAware: 回传classLoader给对象
  • BeabFactoryAware: 回传beanFactory给对象

AbstractAutowireCapableBeanFactory

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 = getBeanClassLoader();
        if (bcl != null) {
          ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
        }
      }
      if (bean instanceof BeanFactoryAware) {
        ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
      }
    }
  }
复制代码

初始化前

初始化前也是Spring提供的一个扩展点BeanPostProcessor#postProcessBeforeInitialization

public interface BeanPostProcessor {
    /**
     * 该方法在bean实例化完毕(且已经注入完毕),在afterPropertiesSet或自定义init方法执行之前
     */
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }
  ...
}  
复制代码

利用初始化前,可以对进行了依赖注入的Bean进行处理

在Spring源码中:

  • InitDestroyAnnotationBeanPostProcessor会在初始化前这个步骤中执行@PostConstruct的方法

  • ApplicationContextAwareProcessor会在初始化前这个步骤中进行其他Aware的回调

    • EnvironmentAware:回传环境变量
    • EmbeddedValueResolverAware: 回传占位符解析器
    • ResourceLoaderAware: 回传资源加载器
    • ApplicationEventPublisherAware: 回传事件发布器
    • MessageSourceAware: 回传国际化资源
    • ApplicationStartupAware: 回传应用其他监听对象,可以忽略
    • ApplicationContextAware: 回传Spring容器的ApplicationContext
@Override
  @Nullable
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
        bean instanceof ApplicationStartupAware)) {
      return bean;
    }

    AccessControlContext acc = null;

    if (System.getSecurityManager() != null) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    }

    if (acc != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
        invokeAwareInterfaces(bean);
        return null;
      }, acc);
    }
    else {
      // 执行aware方法
      invokeAwareInterfaces(bean);
    }

    return bean;
  }
复制代码

初始化

  • 查看当前Bean对象是否实现InitializingBean#afterPropertiesSet接口了,如果实现了就会调用afterPropertiesSet方法
  • 执行BeanDefinition中指定的初始化方法
public interface InitializingBean {

  void afterPropertiesSet() throws Exception;

}
复制代码

初始化后

这是Bean创建的生命周期中的最后一个步骤,也是Spring提供的一个扩展点BeanPostProcessor#postProcessAfterInitialization

In this step, the Bean can be finally processed. AOP in Spring is implemented based on initialization, and the object returned after initialization is the final Bean object.

public interface BeanPostProcessor {
    ...
    /**
     * 在afterPropertiesSet或自定义init方法执行之后
     */
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}
复制代码

Summarize BeanPostProcessor

  • Before instantiation: InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
  • instantiate
  • Instantiate post-processing: MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
  • After instantiation: InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
  • automatic injection
  • Populate properties: InstantiationAwareBeanPostProcessor.postProcessProperties()
  • Aware adjustment
  • Before initialization: BeanPostProcessor.postProcessBeforeInitialization()
  • initialization
  • After initialization: BeanPostProcessor.postProcessAfterInitialization()

Guess you like

Origin juejin.im/post/7086117728649478151