学习笔记——springboot系列_自动装配

前言

所谓spring boot框架,归根结底就是一个bean工厂,将资源类通过一系列的操作装配成各种各样的bean来方便功能的实现。本文想要讲诉清楚的便是一系列的操作过程的逻辑和实现。
就当前的层次来说,可以理解为,无非还是Java虚拟机加载目标class文件,通过封装以后作为资源注册到beanFactory。

通过注解的方式来确定目标class文件

springboot框架说白了就是,封装了spring框架繁杂的配置文件内容,用注解的形式来达到相同的目的。
主要分为三种类型的注解:
第一种为@componentScan和@MapperScan来扫描@repository、@service、@component和@mapper等。带有后四种注解的就是所谓的目标class文件。@componentScan和@MapperScan将扫描带有目标注解的class文件,然后Java虚拟机加载完目标class文件作为beanDefinition对象存入一个hashMap内,这个beanDefinition对象包含的内容就是这个资源类的内容属性,常用的三个属性为,class,autowireMode和constructorArgumentValue。class属性,顾名思义,代表你是那个类的,autowireMode属性,自动装配的模式,可以分为按类型或者是名字等来自动装配,默认是按名字,默认的值为0,想要改变为其他的类型来自动装配,改变默认值为1、2、3对应的值即可,constructorArgumentValue属性,当资源类有多个构造函数的时候,来确定使用资源类的那个构造函数。还有一些零零散散的属性。就不多说了。
第二种为@Bean注解,带有@Bean注解的类可以被识别为目标class文件,然后被Java虚拟机加载成beanDefinition对象,后面和上面的逻辑内容基本一样,就不再叙述。
第三种为@Import注解,@import注解有几种方式,这里用springboot启动类的默认模式作为讲解,点进启动类的@SpringBootApplication注解,会发现有这么一个注解@EnableAutoConfiguration,名字的意思,使能自动配置,功能也是这样,这也是spring boot强大的命名方式带来的便捷之处。继续点进注解,终于发现了我们说的@Import注解,他的参数是一个class对象,AutoConfigurationImportSelector.class,顾名思义,我就不翻译了,继续点击这个类,发现它扩展了很多接口,别慌,都是花把式,你会发现有四个接口都是Aware结尾的,很容易就能想到这是有一个大的和Aware相关的老祖接口,这里暂且不谈,还有一个Ordered接口,也容易想到扩展这个接口来实现一些排序的功能,这里也暂且不谈,那么还剩下一个DeferredImportSelector接口,发现和我们的注解相关,其实我们AutoConfigurationImportSelector这个类要去找的是这个ImportSelector接口,点进DeferredImportSelector接口你会发现它确实继承了ImportSelector接口,而找ImportSelector接口的唯一目的当然是实现它的方法,也就是selectImports(AnnotationMetadata importingClassMetadata),返回的是一个String[]数组,这个数组的内容就是我们的目标的class文件的名字,springboot启动的时候,就会去找这个String[]里面的目标class文件名,加载成beanDefinition对象,注意,我每次说的都是,此时加载为beanDefinition对象,而不是bean。

以上就是三种注解怎么加载目标class文件为beanDefinition对象,和什么是对应的目标class文件的过程。

注册beanDefinition对象为bean

现在我们已经获得了beanDefinition对象,就只剩下最后把这个beanDefinition对象初始化为bean对象就大功告成。当得到beanDefinition对象时,这些beanDefinition会被注册到
相应的BeanDefinitionRegistry,这样容器的启动工作基本完成。当某个请求通过容器的getBean方法请求某个对象,或者因为依赖关系容器需要隐式的调用getBean时,就会触发第二阶段的活动:容器会首先检查所请求的对象之前是否已经实例化完成。如果没有,则会根据注册的BeanDefinition所提供的信息实例化被请求对象,并为其注入依赖。当该对象装配完毕后,容器会立即将其返回给请求方法使用。
在这个beanDefinition对象初始化为bean对象的过程中,我想补充两个接口内容,其实也容易想到,从加载class文件到bean对象的初始化,只是简单的说了一下这条路线的主要站点,行驶的过程中还有很多可以操作的地方,不然也不会有那么的接口,比如上述的以Aware结尾的接口那么多呢是吧,既然扩展了,肯定要干事情,不然扩展干啥。但是这里我想说的还不是上面提到过的接口。
这两个接口是BeanFactoryPostProcessor和BeanPostProcessor,往下看。
补充:BeanFactory接口中主要包含getBean、containBean、getType、getAliases等管理bean的方法,而BeanDefinitionRegistry接口则包含registerBeanDefinition、removeBeanDefinition、getBeanDefinition等注册管理BeanDefinition的方法。

xxxPostProcessor(后置处理器)接口

BeanFactoryPostProcessor接口可以在beanDefinition对象初始化为bean对象的过程中,拦截这个beanDefinition对象,修改上述我提到的beanDefinition对象的属性。这样初始化的bean对象就可以是自定义属性的beanDefinition对象来的。而BeanPostProcessor接口则是可以对已经初始化成bean对象的这个bean再次进行加工操作和修改,然后返回给getBean方法。
再具体一点,随便写一个自定义类,
如MyBeanFactoryPostProcessor类去扩展BeanFactoryPostProcessor接口,发现要重写void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法,这参数的意思不要太明显,上面说过,BeanFactoryPostProcessor接口要操作的是beanDefinition对象,理所当然得先获取一个beanDefinition对象,点进ConfigurableListableBeanFactory接口,会发现BeanDefinition getBeanDefinition(String beanName)方法,通常返回的是扩展了BeanDefinition接口的GenericBeanDefinition类,再次感慨spring的命名方式一如既往的简单直接。既然得到了beanDefinition对象,接下来就是各种set这个beanDefinition的各种属性为我们想要的值,这样bean对象初始化的时候,就会检查BeanFactoryPostProcessor接口,从而初始化成我们自定义的属性,这里用常用三种属性之一的autowireMode属性举例说明。点进GenericBeanDefinition类,发现没啥属性,那就继续找根,点进它的继承类AbstractBeanDefinition,很明显定义了四个静态常量,AUTOWIRE_NO、AUTOWIRE_BY_NAME、AUTOWIRE_BY_TYPE、AUTOWIRE_CONSTRUCTOR,默认的是AUTOWIRE_NO,NO说明没有限制自动装配的条件,换句话说,全都可以。向下看,就是各种get,set各种属性的方法,当然肯定有setAutowireMode,然后你就可以为所欲为了,人家为了方便,还分别为这几个常量定义了0、1、2、3来与之匹配。其他的属性的设置和改变,逻辑都一样,就不说了。
接下来同样流程,定义一个MyBeanFactoryPostProcessor类扩展FactoryPostProcessor接口,发现,好像不用实现什么方法。那就点FactoryPostProcessor接口进去看看,也简单,就两个方法,postProcessBefore/AfterInitialization,一前一后。看了下postProcessAfterInitialization的注释,可以偷梁换柱返回一个FactoryBean,也就是说,我获得bean对象以后,我可以返回一个其他的bean的意思。还有可以进行一些类型检查,设置一些初始化配置等等,反正返回的是Object对象,可能读者不是很理解前面这句话的涵义,请往下接着看,我会在讲解FactoryBean的内容的时候提到,你会有更清晰的认识。那么这两个接口的内容基本就是这些了。继续往下看。

bean实例化阶段的其他接口

其实实例化阶段,spring给我们暴露了很多可以扩展的点,主要分为四个方向。上面的内容我已经提到过两个方向,并详细的说了实现了xxxPostProcessor接口,
接下来,先说上面提到过xxxAware接口方向,Aware接口的作用就是实例化时,spring会帮我们注入对应的:BeanFactory、BeanClassLoader、ResourceLoader、Environment等的实例。也就是为bean对象搭建一个生存环境的功能接口。这部分的知识和内容,我没有实践过,也没具体点进去过具体的实现类,去分析他的源码和方法,这些在后期的内容里,会添加和补充说明,理论来说,每个方向的学习思考逻辑应该都大同小异,想必看了我上诉主讲的PostProcessor接口方向,你对其他方法的学习和用法,应该不是什么问题,所以我主要说他的功能和方向即可。
接下来是第三中,实现InitializingBean接口的方向,顾名思义,这个方法就是在懒加载过程的一些可控的操作了,而什么时懒加载呢,这里可以类比单例模式的DCL模式,你调用getBean的时候,告诉我,你需要了,这时我才去初始化你需要的bean,然后返回给你,并不是我一开始就把所有的bean初始化好,等着你来取。这里,我大胆猜想一下,这个接口的方向,作用可能是,某些bean,我想一开始就初始化好,你取的时候直接返回给你,或者是,某些有关联关系的bean,在你请求一个bean的时候,我直接把和他有某种关系的bean一起初始化了,或者一起返回等等。
接下里是第四种,DisPosableBean方向,点进这个接口,就一个方法,void destroy(),在bean死亡的时候,给它体面的安排一下后事,做到有始有终。

题外话FactoryBean

一直以来的想法都是,spring框架、bean工厂嘛,beanFactory嘛,来配置管理各种bean。突然串进来一个FactoryBean,工厂bean,是个什么玩意?其实吧,看它的后缀为Bean,说明了他还是一个bean,是一个有着工厂性质的接口bean,为什么说它有着工厂性质呢,因为当你获取这个bean对象的时候,它返回的是任意的一个object对象,而不是它本身,所以称之为工厂bean。同样测试一下,写一个MyFactoryBean类扩展FactoryBean接口,发现得实现它的两个方法getObjectType()和getObject(),一个是返回的是任意object对象,一个返回的是这个object对象的class对象。也就是说,当你获取这个自定义MyFactoryBean的bean对象的时候,得到的是上面的两个东西,那这个object对象,你就可以为所欲为,返回你想返回的任意对象。和上面提到的postProcessAfterInitialization接口里面的方法返回的概念差不多,都是为所欲为的概念。

补充

上面就是spring boot自动装配的大致内容了,spring boot就是在上述的大致框架的基础上加上了无数的细节处理而已,后面学习和研究到自动装配的更多源码细节,我会再做补充和总结。

结语

以上内容是个人的一些总结和理解,参考于各种各样的网上资源和自己的一些实践后的思考和总结,如果有错误和不足的地方,希望交流指正,如果对你有帮助,希望一起交流学习,共同进步。
qq:1192375101

你可能感兴趣的:(Java学习笔记,java,spring)