【小家Spring】为脱离Spring IOC容器管理的Bean赋能【依赖注入】的能力,并分析原理(借助AutowireCapableBeanFactory赋能)(上)

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【小家Spring】为脱离Spring IOC容器管理的Bean赋能【依赖注入】的能力,并分析原理(借助AutowireCapableBeanFactory赋能)(上)

前言


咋一看标题,小伙伴们是否还有点小激动呢?觉得这怎么可能呢?


可能我们(大众)都是这样认为:自从用上了Spring这个优秀的框架,一般小伙伴们都是一言不合就把对象塞进Spring的IOC容器里面,交给它来替我们管理。


不可否认的是,把Bean交给Spring管理,确实极其的方便,优点一大把,并且还几乎没有啥缺点。这也就是为何咱们一言不合就把Bean扔给Spring的原因。(在Spring的技术栈里这么做,完全没有问题)


然而,就Spring框架本身而言。它的强大的依赖注入,不仅仅能给自家的Bean使用,还能赋能给容器之外的Bean,快速的把需要注入的对象给它装配好。


本来我也一直以为你想用Spring的依赖注入功能,就得交给Spring容器进行管理。直到我上周看AutowireCapableBeanFactory源码的时候,上面的JavaDoc就清晰的写到了,它还可以为非容器内的Bean服务~


注意:原对象可以不在Spring的IOC容器里,但是需要被依赖注入的成员,就必须是Spring容器管辖的Bean

本篇文章实际用处可能较少(可能在继承某些特殊的第三方框架的时候需要),但是掌握了本篇文章的内容,能让你更加清晰的了解到Spring依赖注入的原理(一般应用开发者不会使用这个接口,但如果你是框架设计者,你有必要了解这个接口)


我们使用的应用上下文ApplicationContext它就提供了

AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;

虽然它不直接继承,但是它允许你拿这个工具去做你需要的事。~~~


Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)


AutowireCapableBeanFactory 的解释


 * Extension of the {@link org.springframework.beans.factory.BeanFactory}
 * interface to be implemented by bean factories that are capable of
 * autowiring, provided that they want to expose this functionality for
 * existing bean instances.


AutowireCapableBeanFactory在BeanFactory基础上实现了对存在实例的管理.可以使用这个接口集成其它框架,捆绑并填充并不由Spring管理生命周期并已存在的实例.像集成WebWork的Actions 和Tapestry Page就很实用.


public interface AutowireCapableBeanFactory extends BeanFactory {
  int AUTOWIRE_NO = 0;
  int AUTOWIRE_BY_NAME = 1;
  int AUTOWIRE_BY_TYPE = 2;
  int AUTOWIRE_CONSTRUCTOR = 3;
  @Deprecated
  int AUTOWIRE_AUTODETECT = 4;
  // 注意这个CreateBean和下面的CrateBean的不同
  //JavaDoc:It does <i>not</> imply traditional by-name or by-type autowiring of properties;
  // 也就是说它只管给你创建Bean,但是不管给你根据Name或者Type进行注入哦
  // 当然,你可以显示在对应属性上指定@Autowired注解,让他也可以达到相同的效果
  <T> T createBean(Class<T> beanClass) throws BeansException;
  void autowireBean(Object existingBean) throws BeansException;
  Object configureBean(Object existingBean, String beanName) throws BeansException;
  Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
  Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
  void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
      throws BeansException;
  void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
  Object initializeBean(Object existingBean, String beanName) throws BeansException;
  Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException;
  Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException;
  void destroyBean(Object existingBean);
  <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
  @Nullable
  Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
  @Nullable
  Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
}


这里就不解释各个方法了,具体参考:

【小家Spring】BeanFactory体系和ApplicationContext体系,两大体系各接口分析、区别和联系


Demo Show


说得可能还是一头雾水,上个例子先看看效果吧:


以createBean() 方法为例
// 准备一个Child类
@Getter
@Setter
public class Child {
  // 注意:这里并没有@Autowired注解的
    private HelloService helloService;
    private String name;
    private Integer age;
}
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
        // ApplicationContext里面是持久AutowireCapableBeanFactory这个工具的,它真实的实现类一般都是:DefaultListableBeanFactory
        AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
        // 我们吧Child的创建过程都交给Bean工厂去帮我们处理,自己连new都不需要了 (createBean方法执行多次,就会创建多个child实例)
        Child child = (Child) autowireCapableBeanFactory.createBean(Child.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
        //简直残暴,没有@Autowired注解都给注入进来了~~~  至于为什么,看看下面的分析,你就知道了
        System.out.println(child.getHelloService()); //com.fsx.service.HelloServiceImpl@6a78afa0
        // 抛出异常 No qualifying bean of type 'com.fsx.bean.Child' available 
        // 能佐证:我们的Bean并没交给Spring容器管理,它只是帮我们创建好了,并把对应属性注入进去了
        Child bean = applicationContext.getBean(Child.class);
        System.out.println(bean);
    }


看到这个现象有没有很惊喜,我们哪怕不是Spring去管理的对象,都能够依赖注入进来容器内的对象,并且,并且连@Autowired注解都不需要。所以更别谈Spring内部的容器,并且还标注了注解的,那就应该更容易去实现了


所以,了解了本文后,再回过头去看看Spring内部的自动化的依赖注入,就会说一句:也就那样嘛,哈哈~


以createBean() 方法为例的源码分析



在上面Demo Show的基础上,我们来看看源码,到底是怎么做到的。

来到AbstractAutowireCapableBeanFactory#createBean:


  @Override
  public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    RootBeanDefinition bd = new RootBeanDefinition(beanClass,  autowireMode, dependencyCheck);
    // 这里看到了,采用的不是单例,而是prototype
    bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    // For the nullability warning, see the elaboration in AbstractBeanFactory.doGetBean;
    // in short: This is never going to be null unless user-declared code enforces null.
    // doc说得很明白,这里返回值永远不可能为null。除非调用者强制return null
    // 注意的是:这里BeanName就是beanClass.getName()
    return createBean(beanClass.getName(), bd, null);
  }
// 最终都调用到了下面这个createBean方法。它也是AbstractBeanFactory提供的一个抽象方法
// 最终也由AbstractAutowireCapableBeanFactory去实现的。 我们熟悉的doGetBean()方法,最终也是调用它来创建实例对象  只是doGetBean()把单例对象都缓存起来了
// 这个方法很单纯:创建一个实例,然后初始化他(给属性们赋值),然后return出去即可
  @Override
  protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
    if (logger.isDebugEnabled()) {
      logger.debug("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;
    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
    }
    // Prepare method overrides.
    // 解析一些@lookup注解之类的  忽略
    try {
      mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
          beanName, "Validation of method overrides failed", ex);
    }
    try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      // 这个之前都解释过了,就不解释了。若BeanPostProcessors 产生了一个代理对象,就不需要我去创建了,就不继续往下走了(AOP都走这里)
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
        return bean;
      }
    }
    catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
          "BeanPostProcessor before instantiation of bean failed", ex);
    }
    try {
      // 重点来了。它是本类的一个protected方法,专门用于处理创建Bean的过程(包括属性赋值之类的)
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isDebugEnabled()) {
        logger.debug("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
    }
    catch (Throwable ex) {
      throw new BeanCreationException(
          mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
  }


这里再看看doCreateBean吧,因为之前有讲过这个方法,这里就看看止看看核心步骤。


  protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args){
  BeanWrapper instanceWrapper = null;
  ...
  //createBeanInstance 是重点(都是返回一个BeanWrapper)  它也是本类的一个protected方法
  instanceWrapper = createBeanInstance(beanName, mbd, args);
  // Bean已经实例化好了,准备初始化吧
  ...
  // 执行MergedBeanDefinitionPostProcessor
  // 处理循环引用,现在若我们Bean不在容器里,肯定是不存在循环引用的(但是我依赖的Bean可能还没创建是真的,也是这里来处理的)
  ...
  // 给Bean实例的各个属性进行赋值 比如调用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation、给属性注入值(并不依赖于@Autowired注解)
  // 执行InstantiationAwareBeanPostProcessor#postProcessPropertyValues等等
  populateBean(beanName, mbd, instanceWrapper);
  // 初始化Bean 执行一些初始化方法init @PostContruct方法等等 
  //BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization等等
  exposedObject = initializeBean(beanName, exposedObject, mbd);
}

综上可以看出,目前最重要的三个步骤为doCreateBean里面的:createBeanInstancepopulateBeaninitializeBean,都在AbstractAutowireCapableBeanFactory这里


相关文章
|
7天前
|
XML Java 数据格式
spring复习02,xml配置管理bean
详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
spring复习02,xml配置管理bean
|
7天前
|
XML Java 测试技术
spring复习01,IOC的思想和第一个spring程序helloWorld
Spring框架中IOC(控制反转)的思想和实现,通过一个简单的例子展示了如何通过IOC容器管理对象依赖,从而提高代码的灵活性和可维护性。
spring复习01,IOC的思想和第一个spring程序helloWorld
|
4天前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
13 4
|
7天前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
29 3
|
7天前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
XML Java API
Spring 依赖注入的方式,你了解哪些?
前言 依赖查找和依赖注入是 Spring 实现 IoC 容器提供的两大特性,相对于依赖查找,Spring 更推崇的是使用依赖注入,本篇先对 Spring 中依赖注入的几种方式进行介绍,后续再分享其实现。
223 0
Spring 依赖注入的方式,你了解哪些?
|
Java 测试技术 开发者
Spring 有哪几种依赖注入方式?官方是怎么建议使用的呢?
IDEA 提示 Field injection is not recommended 在使用IDEA 进行Spring 开发的时候,当你在字段上面使用@Autowired注解的时候,你会发现IDEA 会有警告提示:
288 0
Spring 有哪几种依赖注入方式?官方是怎么建议使用的呢?
|
7天前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
Java Spring 容器
Spring中IoC两种接口和两种依赖注入方式的比较
spring是一个开源框架,是为了解决企业应用程序开发的复杂性而创建的,为J2EE应用程序开发提供集成的框架。简单来说,spring是一个轻量级的控制反转IOC和面向切面AOP的容器框架。spring框架会对定义在配置文件中的bean实例自动管理,这个bean也就是Java实例,Java组件,spring既可以管理标准的javabean,又可以管理普通的Java组件。   spring
1874 0

相关产品

  • 容器服务Kubernetes版
  • 下一篇
    无影云桌面