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

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

源码这里就不再贴了,因为确实比较简单。用一些文字描述即可:


1.invokeAwareMethods:执行一些感知接口Aware的注入

2. postProcessBeforeInitialization:执行后置处理器的此方法。基本上也是执行一些Aware的注入。

—>1. InitDestroyAnnotationBeanPostProcessor在这里会执行@PostConstruct标记的方法

—>2. ApplicationContextAwareProcessor/ServletContextAwareProcessor会实现感知接口的注入

4. invokeInitMethods:先执行InitializingBean#afterPropertiesSet方法,再执行init-method。

5. postProcessAfterInitialization:执行后置处理器此方法。这里面有不少干实事的:

—>1. AbstractAdvisingBeanPostProcessor,AbstractAutoProxyCreator:会把所有的切面保存下来(AOP包下的)

—>2. ApplicationListenerDetector:会把所有的ApplicationListener子类保存起来

—>3. ScheduledAnnotationBeanPostProcessor:会把所有的标注了@Scheduled的方法保存起来

—>4. SimpleServletPostProcessor:会调用Servlet#init的init方法


至于对应的@EventListener注解是什么时候解析的。是它:EventListenerMethodProcessor,它是一个SmartInitializingSingleton,所以它是在preInstantiateSingletons()方法的最后一步去调用的(比如getBean()方法还晚)

由此,我们是可以得出结论的:Spring之外的Bean,SmartInitializingSingleton接口对他是不起作用的。但是,其余的处理器、注解等等都是有用的哦:@PostConstruct、@Autowired等等注解


就这样,就完成结束了我们的Bean的创建、实例化、初始化等等操作。


其它API:autowireBean、configureBean等等



autowireBean:

  @Override
  public Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    final RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
    bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    if (bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
      return autowireConstructor(beanClass.getName(), bd, null, null).getWrappedInstance();
    }
    else {
      Object bean;
      final BeanFactory parent = this;
      if (System.getSecurityManager() != null) {
        bean = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
            getInstantiationStrategy().instantiate(bd, null, parent),
            getAccessControlContext());
      }
      else {
        bean = getInstantiationStrategy().instantiate(bd, null, parent);
      }
      populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean));
      return bean;
    }
  }


和createBean的区别:createBean是全量的。什么各种后置处理器都不执行。而autowire它直接调用策略器实例化了,什么有关实例化的处理器就都不会执行了(所以不能生成代理对象了嘛)(使用较少,但可以绕过一些处理器)


autowireBeanProperties: 相当于只执行了给属性赋值populateBean()(以及相关的处理器)

  @Override
  public void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
      throws BeansException {
    // 构造器注入的模式,这里就不能支持了
    if (autowireMode == AUTOWIRE_CONSTRUCTOR) {
      throw new IllegalArgumentException("AUTOWIRE_CONSTRUCTOR not supported for existing bean instance");
    }
    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    RootBeanDefinition bd =
        new RootBeanDefinition(ClassUtils.getUserClass(existingBean), autowireMode, dependencyCheck);
    bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    BeanWrapper bw = new BeanWrapperImpl(existingBean);
    initBeanWrapper(bw);
    populateBean(bd.getBeanClass().getName(), bd, bw);
  }


    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
        // ApplicationContext里面是持久AutowireCapableBeanFactory这个工具的,它真实的实现类一般都是:DefaultListableBeanFactory
        AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
        //我们也可以自己手动创建一个实例  然后让Spring帮我们自动装配就行  也能正常注入
        Child child = new Child();
        autowireCapableBeanFactory.autowireBeanProperties(child, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
        System.out.println(child.getHelloService()); //com.fsx.service.HelloServiceImpl@175c2241
    }


initializeBean:相当于只执行了初始化Bean的一些操作。。。


  @Override
  public Object initializeBean(Object existingBean, String beanName) {
    return initializeBean(beanName, existingBean, null);
  }


后面的就不一一介绍了,因为有了上面的源码分析,了解其它的就不难了。


AutowireCapableBeanFactory的使用场景


1、首先最大的使用场景就是Spring内部

2、Spring Boot集成Quartz的时候。很好的使用到了此方案。我们在Job类里面使用@Autowired注入的时候,若出现注入不进去的现象。可以考虑使用AutowireCapableBeanFactory进行协助

3、前面说到的继承特定的第三方框架,他们的Bean并不需要交给Spring管理,但是又想用到Spring容器里面的Bean完成一些功能的时候,使用它就特别的方便了。


InstantiationStrategy


本来该策略接口不准备放在此处,但是正所谓说过的话,跪着也要走完啊(上面说过)。因此,那就来吧~

上面分析我们发现,Bean大都最终的实例化操作是交由这个策略器来搞定的,那它是什么呢?


// Interface responsible for creating instances corresponding to a root bean definition.
// 简而言之,就是根据RootBeanDefinition,去实例化一个实例(相当于new了一个对象而已,bean的具体的属性在此时并未赋值)
public interface InstantiationStrategy {
  // 下面是他的三个重载方法
  // owner:这个Bean定义所属的BeanFactory工厂
  // args:构造函数的参数(大多数情况下都用无参构造)
  // factoryBean:factoryMethod  也支持工厂方法方式创建实例(注意此factoryBean非我们所常指的接口:FactoryBean哦~)
  Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner)
      throws BeansException;
  Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
      Constructor<?> ctor, @Nullable Object... args) throws BeansException;
  Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
      @Nullable Object factoryBean, Method factoryMethod, @Nullable Object... args)
      throws BeansException;
}

它的继承结构很简单:


image.png


SimpleInstantiationStrategy


简单实现类,采用实现部分,抽象部分的策略(但是它可不是抽象类,因为我们是可以直接使用它的(如果没有方法注入MethodInjection的去求的话)。只是我们一般都不会直接使用它,而是子类


它的源码逻辑比较简单,伪代码如下:


  if (!bd.hasMethodOverrides()) {
    ...
    // 最后:借助BeanUtils.instantiateClass(ctor, args) 利用构造函数创建实例
  } else {
    return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
  }


CglibSubclassingInstantiationStrategy

留下了包含MethodOverride对象的bd对象定义未做实现,那么CglibSubclassingInstantiationStrategy就是它的一个实现:它采用采用cglib生成之类方式,实例化对象。(当然若不需要生成代理对象,就直接使用父类的功能即可的)


它的源码相对来说比较复杂:主要是静态内部类CglibSubclassCreator它生成一个子类对象去实现方法注入的功能,它内部有cglib动态代理的内容,这里确实就不太适合展开了,AOP再相见吧~


关于方法注入(MethodInjection):


当我们在一个bean中依赖其他的bean时,我们可以注入其他依赖的bean通过set()或者构造器方法。 这样调用get方法的时候返回在bean中注入的实例。但是如果我们希望在每次调用get方法的时候返回新的实例,怎么办呢?


比如单例的A,希望每次使用B的时候都是一个新的对象~

有的伙伴可能就会这么写了:

@Component
public class A {
    @Autowired
    private B b;
    public B getB() {
        return b;
    }
}
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 这里scope指定不是单例
public class B {
}
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
        A a = applicationContext.getBean(A.class);
        // 我们发现,虽然我们给B设置成`prototype`,但是从a里面get出来的每次都还是同一个对象
        System.out.println(a.getB() == a.getB()); //true
        //证明B不是单例了:
        B b1 = applicationContext.getBean(B.class);
        B b2 = applicationContext.getBean(B.class);
        //证明B并不是单例的
        System.out.println(b1 == b2); //false
    }


现在,这个没达到我们的需求嘛。因为每次A类里面使用B的时候,还是同一个实例~


原因:因为A是单例,它只会被实例化一次,因此对应的属性也会被注入一次。所以即使你get()调用了多次,返回的还是第一次赋值的那个属性值


怎么办呢?、这个时候方法注入闪亮登场,我们只需要在A的get方法上加上@Lookup注解,在看看效果:

@Component
public class A {
    @Autowired
    private B b;
    @Lookup // 采用方法注入
    public B getB() {
        return b;
    }
}
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
        A a = applicationContext.getBean(A.class);
        // 不仅仅每次getB都不一样了,我们还发现a已经变成了一个CGLIB的代理对象
        System.out.println(a); //com.fsx.bean.A$$EnhancerBySpringCGLIB$$558725dc@6a6cb05c
        System.out.println(a.getB() == a.getB()); //false
    }


一下子就解决问题了。在上面分析的时候我们看到AbstractAutowireCapableBeanFactory默认采用的创建Bean策略器为


private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();



因此默认就是支持方法注入的,所以当我们方法标注了@Lookup注解,就能达到我们上诉的效果了~


了解了此处,对后续AOP原理讲解的时候,也有非常大的帮助~~~ 看来提前讲解还是不亏的,哈哈


总结


AutowireCapableBeanFactory接口给我们最大的感觉就是:交给Spring管理的Bean,关于Bean的创建、实例化、初始化等都是自动挡。而我们使用此接口可以拆解成手动档,自己来控制Bean的一些行为。


能够有如此的灵活性,还是得益于Spring的分层设计、组件化的、可插拔等等一些设计特针。再次向Spring的设计者致敬,给这个行业做出的巨大贡献~


另外本文分析中,还有些小细节是需要注意的:比如@Autowired注解不是必须的,交给Spring容器管理也不是必须的,所以建议能够了解到每段代码、注解、处理器的具体执行时机,很多问题就迎刃而解了。

相关文章
|
8月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
8月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
752 2
|
12月前
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
287 1
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
10月前
|
Kubernetes Docker Python
Docker 与 Kubernetes 容器化部署核心技术及企业级应用实践全方案解析
本文详解Docker与Kubernetes容器化技术,涵盖概念原理、环境搭建、镜像构建、应用部署及监控扩展,助你掌握企业级容器化方案,提升应用开发与运维效率。
1319 108
|
11月前
|
存储 监控 测试技术
如何将现有的应用程序迁移到Docker容器中?
如何将现有的应用程序迁移到Docker容器中?
783 57
|
8月前
|
监控 Kubernetes 安全
还没搞懂Docker? Docker容器技术实战指南 ! 从入门到企业级应用 !
蒋星熠Jaxonic,技术探索者,以代码为笔,在二进制星河中书写极客诗篇。专注Docker与容器化实践,分享从入门到企业级应用的深度经验,助力开发者乘风破浪,驶向云原生新世界。
810 51
还没搞懂Docker? Docker容器技术实战指南 ! 从入门到企业级应用 !

相关产品

  • 容器服务Kubernetes版