Spring之Bean生命周期源码解析(二)

Spring之Bean生命周期源码解析(二)

  • 回顾
  • 实例化前
  • 实例化
  • 推断构造方法
  • BeanDefinition的后置处理
  • 实例化后
  • 自动注入
  • 填充属性
  • 执行Aware回调接口
  • 初始化前
  • 初始化
  • 初始化后
  • 总结BeanPostProcessor

回顾

Bean的生命周期流程图

Bean的生命周期.png

包扫描流程图

Spring包扫描底层流程.png

实例化前

当前BeanDefinition对应的类被成功加载之后,就可以进行实例化对象了.

但是在Spring中,实例化对象前,Spring提供了一个扩展点,允许用户来控制是否在某个或者某些Bean实例化前做一些启动动作.

这个扩展点叫InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()

需要注意的是这里是有返回值的,如果实现了这个并且返回了一个对象,那么后续Spring的依赖注入也就不会进行了,会跳过一些步骤,直接进行初始化后这一步.

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

实例化

在这一步就会根据BeanDefinition去创建一个对象了.

Supplier创建对象

首先判断BeanDefinition是否设置了Supplier,如果设置了就会调用Supplier#get()得到对象.

@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();
  }
复制代码

工厂方法创建对象

如果没有设置Supplier,就会检查BeanDefinition是否设置了factoryMethod,也就是工厂方法,有两种方式可以设置factoryMethod

方法一

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

对应的类

public class UserService{

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


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

复制代码

方式二

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

对应的CommonService

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

Spring发现当前BeanDefinition方法设置了工厂方法后,就会区分这两种方式,然后调用工厂方法得到对象

注意的是,我们通过@Bean所定义的BeanDefinition是存在factoryMethod和factoryBean的,也就是和上面的方式二非常类似

@Bean所注解的方法就是factoryMethod,AppConfig对象就是factoryBean

如果@Bean所注解的方法是static的,那么对应的就是方式一

推断构造方法

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

可以在这个步骤中,对Bean最终进行处理,Spring中的AOP就是基于初始化后进行实现的,初始化后返回的对象才是最终的Bean对象

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

总结BeanPostProcessor

  • 实例化前: InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
  • 实例化
  • 实例化后置处理: MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
  • 实例化后: InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
  • 自动注入
  • 填充属性: InstantiationAwareBeanPostProcessor.postProcessProperties()
  • Aware回调
  • 初始化前: BeanPostProcessor.postProcessBeforeInitialization()
  • 初始化
  • 初始化后: BeanPostProcessor.postProcessAfterInitialization()

猜你喜欢

转载自juejin.im/post/7086117728649478151