Spring框架源码拥有约108万行代码,如果要把所有的代码都看一遍,是需要花费大量时间和精力,而且很容易跟进一个方法绕进去,所以我们需要抓住Spring源码主干源码和Spring源码对各种设计模式的运用,以及怎么有条不紊的整合各种框架实现可扩展,各种框架是怎么无缝衔接的织入Spring框架的,比如Spring整合mybatis、nacos是在哪里织入Spring的等等。
ps:idea 插件 Statistic 可以统计框架有多少行代码
先将类加载成Bean定义,加载Bean定义有一个步骤,首先读取到我们的配置类,通过我们的配置类,扫描到配置了@Component等注解的类,然后注册成Bean定义,ApplicationContext可以调用BeanFactoryPostProcessor修改Bean定义,调用BeanDefinitionRegistryPostProcessor注册成Bean定义,通过BeanFactory调用getBean(),然后会实例化,填充属性(解析@Autowired、@Value),初始化调用各种Aware,调用initMethod方法,生产过程中会有很多扩展点,最终放在一个Map里面
图诉Bean的生命周期图诉Spring中的扩展接口IOC 控制反转:用来解决层层之间的耦合
Spring是一个IOC的容器,容器里面管理的是各种Bean,IOC控制反转,是一种设计思想,DI是它的实现。
Spring应用的时候一般会
第一步:配置我们的类,不管是xml或者@注解、javaconfig方式配置。第二步:加载Spring上下文,一般2种方式。xml:new ClassPathXmlApplicationContext(“xml”) 注解:new AnnotationConfigApplicationContext(Config.class)第三步:getBean()通过以上应该我们只知道将类注入到IOC容器中
当我们的一个类变成一个Bean的最核心的一个类是什么?是BeanFactory
BeanFactory是Spring顶层核心接口,使用了简单工厂模式(可参考前面提供的设计模式简单学习一下),负责生产bean。
以下面简单demo为了例查看:
@Configuration @ComponentScan public class MainApp { public static void main(String[] args) { ApplicationContext context=new AnnotationConfigApplicationContext(MainApp.class); UserServiceImpl bean = context.getBean("userServiceImpl",UserServiceImpl.class); bean.sayHi(); }getBean()方法
@Override public <T> T getBean(Class<T> requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(requiredType); }Spring上下文(AnnotationConfigApplicationContext)不生产bean,通知getBeanFactory()去生产Bean,getBean()方法即可以获取Bean,也可以生产Bean,这个方法有2个作用。
查看BeanFactory源码,以idea为例,双击shift,搜索BeanFactory找到该类,快捷键 Ctrl + F12查看该类所有的方法。
由一个工程类传入不同类型的参数,动态决定应该创建哪一个产品类
生产获取Bean的工厂有了,那么我怎么读取到Bean呢? 我们有可能是xml配置的,有可能是注解配置的,这样就需要一个 统一的抽象的 读取后存放至一个接口类里面,那个这个统一的接口是什么呢?BeanFactory只负责生产获取Bean,再负责读取就有些不太符合我们单一指责原则。
所以这个统一的接口就是BeanDefinition,Spring顶层核心接口,封装了生产Bean的一切原材料。具体哪些原材料,请看下面提供的信息。
BeanDefinition接口的核心之类AbstractBeanDefinition
或者访问:http://processon.com/chart_image/5f79449de401fd06fd76ff5e.png
下面以一个生活的例子描述下这个几个的关系:
比如我们买新房子要装修,比如需要定制一个衣柜和橱柜
第一步:需要找到一个定制衣柜的衣柜店,定制衣柜。衣柜店不会生产定制衣柜,而是通知一个工厂来生产定制衣柜第二步:衣柜店会有一个设计师,按照你的要求设计出一个图纸,比如:会有颜色款式等的要求,衣柜店负责人通知工厂按照图纸制作一个衣柜。第三步:工厂按照图纸要求制作衣柜,制作好后,送到衣柜店,等待你来取走。如果再定制橱柜,跟上面步骤差不多
衣柜店的角色就是 ClassPathXmlApplicationContext橱柜店的角色就是AnnotationConfigApplicationContext而你就是 一个带有 @Component的class工厂就是BeanFactory颜色和款式就是@Lazy或者@Scope等衣柜就是Bean图纸就是BeanDefinition设计师就是BeanDefinitionRegistry衣柜店肯定不止一个设计师,也有销售推广等,推广人员去市场寻找在潜在客户,比如推广人员在杭州市西湖区某个小区发传单推广,小区一共有1000个,1000个人就是潜在客户推广人员挨家挨户的介绍产品,但是最终只有10个人买了衣柜,这10个客户就是真实客户。
推广人员这个角色就是BeanDefinitionReader市场就是xml和配置类,这里可以看做上面例子的杭州市西湖区某小区。比如:配置类配置了org.spring.study这个包,这个包下有1000个类,而只有10个类配置了@Component、@Service等注解潜在客户就是BeanDefinitionSacnner真实客户就是bean BeanFactory和Application有什么区别?类结构图:
共同:都有生产bean的能力
区别:
FeatureBeanFactoryApplicationContextBean Bean实例化/装配YesYes集成的生命周期管理NoYes自动注册 BeanPostProcessorNoYes自动注册 BeanFactoryPostProcessorNoYes便利的 MessageSource 访问 (国际化)NoYes内置ApplicationEvent 发布机制NoYesSpring中文文档: https://github.com/DocsHome/spring-docs/blob/master/pages/core/overview.md
Bean的生产过程并不是一步到位的,有哪些步骤呢?涉及到Bean的生命周期,有哪些周期? 第一步:实例化,刚才可以看到我们BeanDefinition里面有参数beanClass,直接通过反射就可以拿到bean第二步:填充属性,解析@Autowired、@Value等等第三步:初始化,可配置一些initMethodName,destroyMethodName等第四步:bean基本已成成形,会put到一个Map里面,那么这个Map的key就是beanname,value存的就是bean的实例,而这个Map就是我们大名鼎鼎的单例池也是一级缓存第五步:getBean()的时候,就是直接在Map里面获取实例在初始化的是时候回回调大量的XXXAware接口
BeanNameAwareBeanClassLoaderAwareBeanFactoryAwareEnvironmentAwareEmbeddedValueResolverAwareResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAwareServletContextAware Spring实例化的方式有哪些? 反射:@Component等的方式,在实例化的过程,是由Spring控制的工厂:@Bean标记的方法是工厂方法,工厂可以通过new()来自己控制,比较灵活 扩展点(敲黑板,看重点)因为这个2个扩展节点知识比较多,非常非常非常重要,重要的时说三遍,另写文章,先眼熟一下类名。
在注册Bean定义的时候,还可以修改,比如设计师在设计衣柜的时候,可以修好图纸,只要还没有执行getBean()方法,就好像图纸给了工厂了,但是工厂因为效益好,还没有来的急做,这时候客户突然说,我想换个颜色等,然后设计师改好后,就从新发给工厂
Spring提供扩展接口,让我可以对BeanDefinition(bean定义)进行扩展,这个接口就是BeanFactoryPostProcessor
除了修改还可以注册BeanDefinitionRegistryPostProcessor
Spring除了IOC的实现不用扩展点,剩下的很多功能都是基于扩展点集成的。这就是Spring生态可以做的非常好的原因。
除了Bean定义有扩展点以外,Bean的生命周期也有扩展点BeanPostPorcessor(Bean的后置处理器),在Bean的生命周期中一共会调用9次Bean的后置处理器。
整体脉络图在线查看: https://www.processon.com/view/link/5f606b33e0b34d080d49f0a2