5.2 缓存中获取单例bean

单例在Spring的同一个容器中只会被创建一次,后续在获取bean直接从单例缓存中获取,当然这里也只是尝试加载,首先尝试从缓存中加载,然后在尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时需要依赖上个bean,则直接使用ObjectFactory

  1. AbstractBeanFactory.doGetBean()
  2. public Object DefaultSingletonBeanRegistry.getSingleton(String beanName) {
  3. //参数true设置允许早期依赖
  4. return getSingleton(beanName, true);
  5. }
  6. //DefaultSingletonBeanRegistry
  7. @Nullable
  8. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  9. //检查缓存中是否存在实例
  10. Object singletonObject = this.singletonObjects.get(beanName);
  11. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  12. //为空,则锁定全局变量进行处理
  13. synchronized (this.singletonObjects) {
  14. //如果次bean正在加载则不做处理
  15. singletonObject = this.earlySingletonObjects.get(beanName);
  16. if (singletonObject == null && allowEarlyReference) {
  17. //当某些方法提前初始化的时候会调用 addSingletonFactory 将对应的ObjectFactory 初始化策略存储在singletonFactories
  18. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  19. if (singletonFactory != null) {
  20. singletonObject = singletonFactory.getObject();
  21. this.earlySingletonObjects.put(beanName, singletonObject);
  22. this.singletonFactories.remove(beanName);
  23. }
  24. }
  25. }
  26. }
  27. return singletonObject;
  28. }

上述方法涉及到循环依赖的检查,以及设计很多变量的记录存取。这个方法首先尝试从singletonObject里面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面后去beanName对应的ObjectFactory,然后调用ObjectFactory的getObject来创建bean,并放到earlySingletonObjects里面,并且从singletonFactories里面remove掉这个ObjectFactory。
这里涉及用于存储bean的不同map

  • singletonObjects:用于保存BeanName和创建bean实例之间的关系,bean name->bean instance
  • earlySingletonObjects:用于保存beanName和创建bean实例之间的关系,与singletonObjects的不同之处在于,当一个单例bean被放到这里面后,那么当bean还在创建过程中,就可以通过getBean方法获取到了,其目的是用来检查循环引用。
  • singletonFactories:用于保存BeanName和创建bean工厂之间的关系

5.3 从bean的实例中获取对象

在getBean方法中,getObjectForBeanInstance 是个高频使用的方法。总之,我们得到bean的实例后要做的第一步就是调用这个方法来检测一下正确性。其实就是检测当前bean是否是FactoryBean类型的Bean,如果是,那么需要调用该bean对应的FactoryBean实例中的getObject作为返回值。
无论从缓存中获取到的bean还是通过不同的scope策略加载到的bean都只是最原始的bean状态,并不一定是我们最终想要的bean。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法返回的bean 。而getObjectForBeanInstance就是完成这个工作的。

image.png

AbstractAutowireCapableBeanFactory.java

  1. @Override
  2. protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
  3. return applyBeanPostProcessorsAfterInitialization(object, beanName);
  4. }
  5. public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
  6. throws BeansException {
  7. Object result = existingBean;
  8. for (BeanPostProcessor processor : getBeanPostProcessors()) {
  9. Object current = processor.postProcessAfterInitialization(result, beanName);
  10. if (current == null) {
  11. return result;
  12. }
  13. result = current;
  14. }
  15. return result;
  16. }

Spring在获取bean的规则中有这样一条:尽可能保证所有bean初始化后调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理,这在实际开发中可以针对此特性设计自己的业务逻辑。

5.7.4 初始化bean

bean的配置中有个init-method的属性,这个属性的作用是在bean实例化前调用init-method指定的方法根据用户业务执行相应的实例化。

AbstractAutowireCapableBeanFactory.java

  1. protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
  2. if (System.getSecurityManager() != null) {
  3. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  4. invokeAwareMethods(beanName, bean);
  5. return null;
  6. }, getAccessControlContext());
  7. }
  8. else {
  9. //对特殊的bean处理:Aware BeanClassLoadWare BeanFactoryAware
  10. invokeAwareMethods(beanName, bean);
  11. }
  12. Object wrappedBean = bean;
  13. if (mbd == null || !mbd.isSynthetic()) {
  14. //应用后处理器
  15. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  16. }
  17. try {
  18. //激活用户自定义init方法
  19. invokeInitMethods(beanName, wrappedBean, mbd);
  20. }
  21. catch (Throwable ex) {
  22. throw new BeanCreationException(
  23. (mbd != null ? mbd.getResourceDescription() : null),
  24. beanName, "Invocation of init method failed", ex);
  25. }
  26. if (mbd == null || !mbd.isSynthetic()) {
  27. //后处理器应用
  28. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  29. }
  30. return wrappedBean;
  31. }

1 激活Aware方法

spring提供了一些相关接口,比如BeanFactoryAware ApplicationContextAware ResourceLoaderAware 等。这些Aware接口的bean在被初始化之后,可以取得一些响应的资源,例如在实现BeanFactoryAware的bean在初始化后,Spring容器将注入BeanFactory实例。

  1. public class Test implements BeanFactoryAware {
  2. private BeanFactory beanFactory;
  3. //声明 bean的时候 spring 自动注册 BeanFactory
  4. @Override
  5. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  6. this.beanFactory = beanFactory;
  7. }
  8. public void testAware(){
  9. //从 beanFactory中获取
  10. final Helllo hello = (Helllo) beanFactory.getBean("hello");
  11. hello.say();
  12. }
  13. }

2 处理器的应用

BeanPostProcessor,这是spring中一个亮点,给用户充足的权限去更改和扩展spring。BeanPostProcessor的使用位置:在调用客户自定义初始化方法前以及调用自定义初始化方法后分别调用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization。使用户可以根据自己的业务需求进行响应的处理。

3 激活自动定义的init方法

客户定制的初始化方法除了我们熟知的使用配置init-method之外,还有使用自定义的bean实现InitializingBean 接口,并在afterPropertiesSet 中实现自己的初始化业务逻辑。
init-methodafterPropertiesSet 都是在初始化bean时执行,执行顺序是 afterPropertiesSet 先执行,而init-method 后执行。

AbstractAutowireCapableBeanFactory.java

  1. protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
  2. throws Throwable {
  3. boolean isInitializingBean = (bean instanceof InitializingBean);
  4. if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
  5. if (logger.isTraceEnabled()) {
  6. logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
  7. }
  8. if (System.getSecurityManager() != null) {
  9. try {
  10. AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
  11. ((InitializingBean) bean).afterPropertiesSet();
  12. return null;
  13. }, getAccessControlContext());
  14. }
  15. catch (PrivilegedActionException pae) {
  16. throw pae.getException();
  17. }
  18. }
  19. else {
  20. //属性初始化后的处理
  21. ((InitializingBean) bean).afterPropertiesSet();
  22. }
  23. }
  24. if (mbd != null && bean.getClass() != NullBean.class) {
  25. String initMethodName = mbd.getInitMethodName();
  26. if (StringUtils.hasLength(initMethodName) &&
  27. !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
  28. !mbd.isExternallyManagedInitMethod(initMethodName)) {
  29. //调用自定义初始化方法
  30. invokeCustomInitMethod(beanName, bean, mbd);
  31. }
  32. }
  33. }