导图社区 spring源码解读
当您打开导图会惊奇的发现其中的大礼,不仅含有spring源码解读而且还阐述了循环依赖,作用域等内容,相信对您的学习有所帮助 1.创建beanfactory梳理完成;2.单例实例化过程梳理完成;3.循环依赖过程梳理完成;4.未完成aop梳理
编辑于2022-08-17 08:28:55 北京市spring源码解读
入口
XML方式解读源码 new ClassPathXmlApplicationContext("spring.xml");
setConfigLocations(configLocations);涉及到模糊匹配:不重要
refresh();容器初始化核心方法
模板设计模式:get到了吗 这个方法是父类的模板方法. 不同的子类有不同实现. 比如: ClassPathXmlApplicationContext FileSystemXmlApplicationContext AnnotationConfigApplicationContext EmbeddedWebApplicationContext
prepareRefresh();准备初始化:不重要
obtainFreshBeanFactory(); xml 方式解读这一步,为了铺垫注解解读
创建beanfactory 解析xml 封装成BeanDefinition
refreshBeanFactory(); 模板方法
getBeanFactory(); 模板方法
AbstractRefreshableApplicationContext类
模板设计模式: 由于实例化的的是ClassPathXmlApplicationContext 这个类继承自 AbstractXmlApplicationContext 又继承 AbstractRefreshableConfigApplicationContext 所以此处 调用的是AbstractRefreshableConfigApplicationContext的refreshBeanFactory()方法.
refreshBeanFactory();方法
如果beanfactory不为空,清空
DefaultListableBeanFactory beanFactory = createBeanFactory(); 实例bean工厂
由于代码过深. 读到后面竟然不知道是调用此类的解析方法.
customizeBeanFactory(beanFactory);
设置是否允许循环依赖 是否允许相同名称的bean 注册为不同Bean实现
loadBeanDefinitions(beanFactory); 解析xml对象.并将xml中的标签解析成beandefinition对象
类:AbstractXmlApplicationContext 方法:loadBeanDefinitions
模板设计模式: 由于实例化的的是ClassPathXmlApplicationContext 这个类继承自 AbstractXmlApplicationContext 此处调用 继承类中的loadBeanDefinitions方法
new XmlBeanDefinitionReader(beanFactory);
委托模式: get到了吗 委托的核心: 持有了被委托对象的引用.
设置环境
beanDefinitionReader.setResourceLoader(this); 设置上下文ApplicationContext
ApplicationContext是实现了ResourceLoader接口的 关系: ClassPathXmlApplicationContext 的顶层父类 DefaultResourceLoader 实现了ResourceLoader接口
loadBeanDefinitions(beanDefinitionReader);
Resource[] configResources = getConfigResources(); 第一进入这里指定为空.跳过
String[] configLocations = getConfigLocations(); 这里是字符串数组{"spring.xml"}
reader.loadBeanDefinitions(configLocations);
1.遍历多个配置文件解析loadBeanDefinitions(location); 2.调用loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) 本类的实现
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); 将字符串spring.xml文件路径 按照流的方式封装成resource 这里涉及到模糊匹配.绝对不深入看
int count = loadBeanDefinitions(resources); 模板设计模式
委托的是XmlBeanDefinitionReader类 调用的也就是XmlBeanDefinitionReader类中的loadBeanDefinitions(Resource resource)方法
将resource转换成 inputResource 这个是jdk sax解析的对象 InputStream inputStream = encodedResource.getResource().getInputStream();
再将流转换成InputSource inputSource = new InputSource(inputStream);
doLoadBeanDefinitions(inputSource, encodedResource.getResource());
beandefinition 是spring实例化必须的对象 根据 对象中属性实例化 通过sax解析成docment对象
将inputresource转换成docment;
sax解析 将resouce 解析成docment对象. 了解即可
registerBeanDefinitions(doc, resource); 将docment封装成BeanDefinition
createBeanDefinitionDocumentReader(); 委托
documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 委托解析
doRegisterBeanDefinitions(doc.getDocumentElement());
解析根root节点
preProcessXml(root);模板模式
parseBeanDefinitions(root, this.delegate);
解析根节点
parseDefaultElement(ele, delegate); 循环解析默认标签
解析import标签
解析别名标签
processBeanDefinition(ele, delegate); 解析bean标签
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 解析docment 封装成beandefinition
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); 解析docment 封装成beandefinition
创建GenericBeanDefinition对象
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
解析bean标签并装进创建的对象中
bean标签上的属性解析
abstract
lazy-init
autowire
depends-on
autowire-candidate
primary
init-method
destroy-method
factory-method
@Bean注解的支撑.
子标签的解析
lookup-method
replaced-method
constructor-arg
property
封装类: mutableProperityValues constractorArgsValues methodOverride
第一个是标签解析后的封装了
List<propertyValue>
第二个是构造函数解析后的封装类
List<constactorValue>
第三个是
将结果封装成BeanDefinitionHolder返回
有名称.有别名.和beandefinitiaon
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 装饰者模式;SPI思想
配置文件中读取配置
spring.handers文件
namespacehander的实现类
根据namespaceurl 获取处理类
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 对beandefinition对象缓存注册
DefaultListableBeanFactory类的 registerBeanDefinition方法.
如果不知道为什么调用这个方法. 注意看DefaultListableBeanFactory. 这个在创建beanfactory的时候.就是这个类型对象. 所以此处调用此类的注册方法
beandefinitionNames 所有的bean名称都在这里
beandefinitionMap 所有的映射关系
delegate.parseCustomElement(ele); 循环解析自定义标签
scan扫描标签过程 此步开始,后续代码注解方式解读 首选了解spi思想.通过spi找到scan扫描的处理类 从处理类开始解读
最终获取包含service component两种注解的文件
1:扫描基本包目录下的.class文件
2: 从metadata中拿到获取基本信息,判断文件中包含在include-filer中的注解类
3: 将属性封装到genericbeandefinition对象中,并注册到spring容器中
4: 注册组件进spring容器中.(完成注册) 其中注册了几个比较重要的BeanPostProcessor类, autowire-xx,common-xx,configuration-xx
postProcessXml(root);模板模式
this.beanFactory = beanFactory;解析完赋值
getBeanFactory();
prepareBeanFactory(beanFactory);设置属性:不重要
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
运行时 动态调整beandefinition的增删改查的操作 BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor 完成自定义对这两个接口实现的调用 实现: 自定义类实现BeanDefinitionRegistryPostProcessor 接口 在重写方法中得到的register.就是beandefinitionregister的容器类.可以得到所有的beandefinition从而增删改查
获取自定义实现了BeanDefinitionRegistryPostProcessor接口的所有类的BeanDefinition对象的beanName
判断是否实现了排序接口
排序
调用自定义实现类的具体方法
有排序的,不排序, 排序还分为两种.所以方法有点大.核心逻辑如上
registerBeanPostProcessors(beanFactory);
实现了BeanPostProcessor接口的类实例化, 并且加入到BeanFactory中. 与上一步的逻辑类似. 注:有一些接口是在实例化之前就注册过的. 比如autowirebeanpostprocessor, commonXXX,confiurationXX
拿到工程里面所有实现了BeanPostProcessor接口的类,获取到BeanDefinition的名称
提前实例化BeanPostProcessor类型的bean,然后bean进行排序
注册到BeanFactory中
initMessageSource();国际化
initApplicationEventMulticaster();初始化事件管理类
onRefresh();
模板设计模式(冗余设计): 此空方法在boot中作为扩展类实现内嵌tomcat启动
registerListeners()
finishBeanFactoryInitialization(); 实例化
注解autowire实现过程 注解resource实现过程 ioc原理 aop原理
遍历所有bean,初始化所有非懒加载单例bean
父子BeanDefinition合并:大部分情况不执行
假如一个类有parent属性.指向父类;
如果不是抽象的,单例的,非懒加载的就实例化
先从缓存中拿,第一次拿不到
父子BeanDefinition合并
如果有依赖类dependsOn先实例化依赖类
如果是单例>>实例化
将bean放入正在实例化的容器中
这个容器的作用 阻断有参构造函数循环依赖
调用匿名函数中实例化bean操作
创建实例
通过反射拿到Class对象
如果有FactoryMethodName属性
这个方法是反射调用类中的 factoryMethod 方法。不要深究参数怎么来的. 这要知道@Bean 方法的原理, 实际上 spring 会扫描有@bean 注解的方法, 然后把方法名称设置到 BeanDefinition 的 factoryMethod 属性中, 接下来就会调到这一步中的方法实现@Bean 方法的调用。
寻找当前正在实例化的bean中有@Autowired注解的构造函数 一般不走这里
determineConstructorsFromBeanPostProcessors 这个方法是 BeanPostProcessor 接口类的首次应用, 最终会调到 AutowiredAnnotationBeanPostProcessor 类的方法, 在方法中会扫描有注解的构造函数然后完 成装配过程。 然后把有@Autowired 注解的构造函数返回。 包装成beanwraperimpl对象
循环所有的beanpostprocessor 拿到构造函数就返回
如果属于SmartInstantiationAwareBeanPostProcessor
AutowireXXX,调用的是这个类中的方法.只有这个类有实现. 也就是只有auwire注解标注的构造函数才能拿到
获取bean中所有的构造器
循环构造器,判断是否增加了autowire注解.获取注解的属性值 封装到数组变量中返回
如果参数是引用类型,一定触发引用类型的getBean实例化操作
上一步构造函数不为空,反射实例化.
参数获取部分不要看.只看最有一句实例化即可. bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
无参构造函数的实例化
大部分 情况走无参构造函数 包装成beanwraperimpl对象 就是反射实例化.
对实例中属性的装配过程
实例化了对象本身. 属性还未实例化. //CommonAnnotationBeanPostProcessor 支持了@PostConstruct,@PreDestroy,@Resource注解 //AutowiredAnnotationBeanPostProcessor 支持 @Autowired,@Value注解 //BeanPostProcessor接口的典型运用,这里要理解这个接口
postProcessMergedBeanDefinition
只有autowiredannotationXXX的类中实现了这个方法. 1、扫描类里面的属性或者方法 2、判断属性或者方法上面是否有@PostConstruct @PreDestroy @Resource注解 3、如果有注解的属性或者方法,包装成一个类
收集
1、看缓存里面有没有 InjectionMetadata 对象 2、从类中获取所有 Field 对象,循环 field 对象,判断 field 有没有@Resource 注解, 如果有注解封装成 ResourceElement 对象 3、从类中获取所有 Method 对象,循环 Method 对象,判断 Method 有没有@Resource 注解,如果有注解封装成 ResourceElement 对象 4、最终把两个 field 和 Method 封装的对象集合封装到 InjectionMetadata 对象中
反射
bean创建完成后singletonsCurrentlyInCreation要删除该bean
创建对象成功时,把对象缓存到singletonObjects缓存中,bean创建完成时放入一级缓存
如果是多例
天生懒加载
将bean放入正在实例化容器
创建bean
遍历所有bean,处理初始化后的回调
总结
主题
标签
id
name
autowire
设置false. 依赖注入 时候忽略
primary
lookup-method
寻找一个方法.lookup方法 注入的是bean 返回 代理模式
methodoveride 包装类
lookupoverride
replaceoverride
replaced-method
项目封板后扩展的牛逼属性 一个需要替换的方法名称 另一个属性是 方法内参数的类型集合 解决有重载方法确定唯一方法的方式
实现类必须实现: MethodReplacer
mutablePropertValues 属性封装类
数据结构: list<property> 里面是key-value结构的对象
constractArgmentvalue 构造函数封装类
作用域
单例
放在singletonObjects缓存中管理
多例
没没有缓存
factoryBean接口
factoryBean的缓存中独立管理
循环依赖
假设A依赖B.B依赖A
A类单例初始
将A加入到正在实例化容器
将A加入到三级缓存
然后依赖注入,触发getBean操作.实例化B
同样实例化B.
将B的对象加入到正在实例化容器
属性依赖入驻触发getBean A 操作
从缓存中拿到了半成品A.并升级缓存返回
结束B实例化.放入1级缓存
结束A实例化,放入1级缓存
装饰者模式
房子类
人
物
编年
2001年的房子
重写人的方法,.人=父亲,母亲,我
重写物的方法,.物=手电
2002年的房子>>继承2001
重写人的方法,首先调用supper.人. =父亲+母亲+我+妻子
重写物的方法,首先调用supper.物 = 手电+冰箱
....
装饰者
持有了房子的引用
装饰者方法 核心是持有了被装饰的引用