傻瓜源码-内容简介 |
---|
🤪【职场经验】(持续更新) 精编短文:如何成为值钱的Java开发-指南 如何平常学习、如何书写简历、引导面试官、系统准备面试、选择offer、提升绩效、晋升TeamLeader..... |
🧐【源码解读】(持续更新) <br/>1. 源码选材:Java架构师必须掌握的全部框架和类库源码<br/>2. 内容大纲:按照“企业应用Demo”讲解执行源码:总纲“阅读指南”、第一章“源码基础”、第二章“相关Java基础”、第三章“白话讲源码”、第四章“代码解读”、第五章“设计模式”、第六章“附录-面试习题、相关JDK方法、中文注释可运行源码项目” 3. 读后问题:粉丝群答疑解惑 |
已收录:HashMap、ReentrantLock、ThreadPoolExecutor、《Spring源码解读》、《Dubbo源码解读》..... |
🤩【面试题集】(持续更新)<br/>1. 面试题选材:Java面试常问的全部面试题和必会知识点<br/>2. 内容大纲:第一部分”注意事项“、第二部分“面试题解读”(包括:”面试题“、”答案“、”答案详解“、“实际开发解说”) 3. 深度/广度:面试题集中的答案和答案详解,都是对齐通常面试要求的深度和广度 4. 读后问题:粉丝群答疑解惑 |
已收录:Java基础面试题集、Java并发面试题集、JVM面试题集、数据库(Mysql)面试题集、缓存(Redis)面试题集 ..... |
🤤【粉丝群】(持续更新) <br/>收录:阿里、字节跳动、京东、小米、美团、哔哩哔哩等大厂内推 |
😛 做者介绍:Spring系源码贡献者、世界五百强互联网公司、TeamLeader、Github开源产品做者 😛 做者微信:wowangle03 (企业内推联系我) |
加入个人粉丝社群,阅读更多内容。从学习到面试,从面试到工做,从 coder 到 TeamLeader,天天给你答疑解惑,还能有第二份收入!html
本书建议分为两个学习阶段,掌握了第一阶段,再进行第二阶段;java
源码项目中的注释含义;git
如下注释的源码,暂时不深刻讲解:面试
代码示例 1spring
public class PersionA { private PersionB pb; public PersionB getPb() { return pb; } public void setPb(PersionB pb) { this.pb = pb; } }
代码示例 2sql
public class PersionB { private PersionA pa; public PersionA getPa() { return pa; } public void setPa(PersionA pa) { this.pa = pa; } }
代码示例 3 application.xml 配置文件数据库
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id="persionA" class="org.springframework.demo.PersionA"> <property name="pb" ref="persionB"/> </bean> <bean id="persionB" class="org.springframework.demo.PersionB"> <property name="pa" ref="persionA"/> </bean> </beans>
代码示例 4 启动 Spring 设计模式
public class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml"); PersionA persion = (PersionA) context.getBean("persionA"); System.out.println(persion.getPb()); } }
暂时由“基础入门 Demo”代替,”企业应用 Demo “以及配套的第 2 版《Spring 源码解读》正在修改中...。缓存
代码示例 1 接口微信
public interface Person { public abstract void eat(); }
代码示例 2 实例化接口
public class Demo { public static void main(String[] args) { // 使用 Lambda 直接建立 Persion 接口实例 Person p1 = () -> System.out.println("eat something!"); // 打印结果:eat something! p1.eat(); } }
直接实例化接口适用于在多个不一样的调用场合,抽象方法会有不一样实现逻辑的场景。反过来想,若是不使用 Lambda 建立 Persion 接口实例,想要在不一样调用场合,执行不一样实现逻辑,就必须为每一个场合定义一个实现了接口的类,而后在实现类的方法里实现对应逻辑。这样比较,使用 Lambda 表达式直接建立接口实例是否是大大简化了代码呢!
1. Spring 中的对象种类
在”企业应用 Demo“中,有涉及到两种对象:Pojo、Bo;
ClassPathXmlApplicationContext(Bo),继承自 AbstractRefreshableConfigApplicationContext ,调用构造函数实例化的同时,启动了 Spring ;在“企业应用 Demo”中主要负责建立 DefaultListableBeanFactory 工厂对象和 XmlBeanDefinitionReader 对象来执行逻辑。
代码示例 重要成员变量
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { // 继承自 AbstractRefreshableConfigApplicationContext // configLocations 表示 application.xml 配置文件的路径,能够配置多个配置文件,例:["classpath*:applicationContext.xml"] private String[] configLocations; // 继承自 AbstractRefreshableApplicationContext // beanFactory 表示 DefaultListableBeanFactory 实例,总的来讲就是用于生成 Bean 的工厂。好比:生成目标对象(例:PersionA)。 private DefaultListableBeanFactory beanFactory;
XmlBeanDefinitionReader(Bo),简称:XmlBean定义读取器;负责读取 application.xml 配置文件,解析成 Resource 实例(Spring 定义的,是用来封装文件资源的类),再根据 Resource 实例获取到的 inputStream 输入流,转化成 Document 实例;而后交由 DefaultBeanDefinitionDocumentReader 对象进行下一步操做。
代码示例 重要成员变量
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { // resourceLoader 表示 ClassPathXmlApplicationContext 实例,负责读取 applicaiton.xml 文件为 Resource 实例 private ResourceLoader resourceLoader; // documentLoader 负责将表明 Resource的inputStream输入流转换成 Document 对象 private DocumentLoader documentLoader = new DefaultDocumentLoader(); // resourcesCurrentlyBeingLoaded 保存当前线程加载了的 application.xml 配置文件(包括<import/> 标签引进的 xml 资源),用来检查 <import/> 形成的循环导入 private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal<>("XML bean definition resources currently being loaded"); // 继承自 AbstractBeanDefinitionReader // registry 表示 DefaultListableBeanFactory 实例,XmlBeanDefinitionReader 是经过构造函数获取到并持有的这个对象,是为了向后续逻辑传递下去 private final BeanDefinitionRegistry registry;
DefaultBeanDefinitionDocumentReader(Bo),简称:Bean 定义 Document 读取器;负责读取 Document 实例中的节点信息,如:< bean/>、< import/> 等;而后交由 BeanDefinitionParserDelegate 对象进行下一步操做。
代码示例 重要成员变量
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { // readerContext 表示 XmlReaderContext 实例,Xml读取器上下文 // 做用:为了将 XmlBeanDefinitionReader 实例、 Resource 实例、DefaultListableBeanFactory 实例等 统一封装到XmlReaderContext 里,向后传递使用 private XmlReaderContext readerContext; // delegate 表明 BeanDefinitionParserDelegate 实例;负责将 Document 对象(例如:< bean/>)装载为 GenericBeanDefinition private BeanDefinitionParserDelegate delegate;
BeanDefinitionParserDelegate(Bo),简称:Bean 定义解析代理;负责将 Document 对象(例如:< bean/>)装载成 GenericBeanDefinition 对象;而后交由 DefaultListableBeanFactory 对象进行下一步操做。
代码示例 重要成员变量
public class BeanDefinitionParserDelegate { // readerContext 表示 XmlReaderContext 实例,上文提过,是Xml读取器上下文 // 用于从 XmlReaderContext 里获取 DefaultListableBeanFactory 实例等对象) private final XmlReaderContext readerContext;
GenericBeanDefinition(Pojo),简称:通用 Bean 定义;是用来装载 < bean/> 配置的实体类。
代码示例 重要成员变量
public class GenericBeanDefinition extends AbstractBeanDefinition { // beanClass 对应<bean class=""/>中的 class 值,一开始会被赋值为 class 设置的字符串,后面会被赋值为解析后的 Class 对象 private volatile Object beanClass; // 继承自 AbstractBeanDefinition // propertyValues 是保存 <property/> 信息的实体类 private MutablePropertyValues propertyValues;
BeanDefinitionHolder(Pojo),简称:Bean定义持有者;负责持有 GenericBeanDefinition 对象(也就是说 GenericBeanDefinition 对象是 BeanDefinitionHolder 一个成员变量),在“企业应用 Demo”中,只起到数据传输的做用。
BeanDefinitionHolder 的必要性和 BeanNameAware 相关;”企业应用 Demo“不涉及。
代码示例 重要成员变量
public class BeanDefinitionHolder implements BeanMetadataElement { // beanDefinition 表示 GenericBeanDefinition 实例;用于装载从 application.xml 配置文件中解析出来的 < bean/> private final BeanDefinition beanDefinition; // beanName 表示 <bean/> 在 Spring 中的名字,通常为 <bean id=""/> 中的 id 值 private final String beanName;
DefaultListableBeanFactory(Bo);总的来讲就是生成 Bean 的工厂。在”企业应用 Demo“中,主要负责根据 GenericBeanDefinition 对象,生成目标对象(例:PersionA)并注入属性值,放到 Map<String, Object> singletonObjects 里保存起来,供应用程序使用。
代码示例 重要成员变量
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { // beanDefinitionNames 用于存放从 application.xml 文件中解析出来的 beanName(通常为 <bean/>标签中的 id 值),按注册顺序排列 private volatile List<String> beanDefinitionNames = new ArrayList<>(256); // 数据结构:{beanName -> GenericBeanDefinition 对象},用于后续逻辑根据 beanName 获取 GenericBeanDefinition 实例来用 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); // 继承自 AbstractBeanFactory // 数据结构:{beanName -> RootBeanDefinition 实例} 缓存,用于防止重复建立 beanName 的 RootBeanDefinition private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256); // 继承自 DefaultSingletonBeanRegistry // singletonsCurrentlyInDestruction 用于标记 Spring 是否处在销毁单例的过程,默认为false;若是设置为 true,建立单例bean的时候,就会抛出 BeanCreationNotAllowedException 异常 private boolean singletonsCurrentlyInDestruction = false; /** * * 如下成员变量,参考下一节“循环依赖”,进行理解 * */ // 继承自 DefaultSingletonBeanRegistry // singletonsCurrentlyInCreation 中存储的beanName都是处于建立过程当中的 // 当该目标对象建立完成后,会将对应的 beanName 从 singletonsCurrentlyInCreation 集合中剔除掉 // 做用:主要用于解决 IOC 循环依赖的问题 private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 继承自 DefaultSingletonBeanRegistry // 数据结构:{beanName ->单例 bean 对象(例:PersionA 实例)} ,也被称为一级缓存; // 添加场景:在“企业应用 Demo”中,当 application.xml 中定义的 bean 对象被彻底实例化后(彻底实例化是指实例化并注入属性值后),则会被放入本缓存中 // 做用:单例 bean 会被放到这个缓存里,当应用系统想要获得 Spring 管理的 <bean/> 时(例:context.getBean("persion");),就能够直接从这个缓存里获取 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 继承自 DefaultSingletonBeanRegistry // 数据结构:{beanName —> ObjectFactory 接口的实现类实例} ,也称为三级缓存 // ObjectFactory 是生产目标对象的工厂接口;不一样场景下,生成对象的逻辑不一样,因此这里使用了工厂接口(好比:生成 AOP 代理对象和经过构造函数生成普通对象等) // 添加场景:在“企业应用 Demo”中,当 bean 对象(例:PersionA 实例)实例化后,没有注入属性值以前,会放入本缓存; // 移除场景:在“企业应用 Demo”中,当 bean 对象彻底实例化后,则会从本缓存中剔除掉 // 做用:在“企业应用 Demo”中,singletonObjects 存放的 value 值是 lambda 表达式建立的 ObjectFactory 接口实例; // singletonFactories 是建立目标对象过程当中,用于存放处于中状态对象的临时容器 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 继承自 DefaultSingletonBeanRegistry // 数据结构:{beanName -> bean 对象(例:PersionA 实例)} ,是提早曝光的单例对象缓存,也称为二级缓存; // 添加场景:在“企业应用 Demo”中,当 bean 对象(例:PersionA 实例)实例化后,发现成员变量指定了其它 Spring 管理的 <bean/> 对象(例:PersionB 实例),而且这个 <bean/> 对象(例:PersionB 实例)存在于 singletonsCurrentlyInCreation ,也存在于三级缓存中,就会把 PersionB 对象从三级缓存中移除,放到二级缓存里;(若是未发生过循环依赖的场景,二级缓存从始至终没有存在过值) // 移除场景:在“企业应用 Demo”中,当 bean 对象彻底实例化后,则会从本缓存中剔除掉 // 做用:用于解决 IOC 循环依赖的问题 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
1. 问题
若是 persionA 依赖 persionB ,persionB 依赖 persionA ,Spring 是如何初始化 PersionA 和 PersionB 的?(这个现象称之为”循环依赖“)
2. 答案
persionA | persionB |
---|---|
1.要开始建立 persionA 对象以前,向 singletonsCurrentlyInCreation 添加该对象的对应 beanName(旨在标记 persionA 处于’建立中‘) | |
2.建立完 persionA 对象后,再把persionA 对象存在三级缓存中,再准备开始注入属性 | |
3.注入属性时,发现依赖 persionB ,要建立 persionB 对象 | |
总结:这时,persionA 对象的 pb 属性为空;三级缓存包含 persionA | |
1.要开始建立 persionB 对象以前,向 singletonsCurrentlyInCreation 添加该对象的对应 beanName(旨在标记 persionB 处于’建立中‘) | |
2.建立完 psersionB 对象后,再把 persionB 对象存在三级缓存里,再准备开始注入属性 | |
2.注入属性时,发现依赖 persionA 对象 | |
3.建立 persionA,发现 singletonsCurrentlyInCreation 存有相应 beanName(PersionA 处于'建立中' ),而且保存在三级缓存里,则直接从三级缓存中移除 PersionA 对象,而后放到二级缓存里 | |
4.将 persionA 对象注入到 persionB 对象的 pa 属性里 | |
5.从三级缓存中删掉 persionB 对象,放到一级缓存里 | |
总结:这时,persionB 对象的 pa 属性不为空,可是 pa 属性(persionA)的 pb 属性为空;二级缓存包含 persionA,一级缓存包含 persionB | |
4.得到 persionB 对象,放到 pb 属性里 | |
5.从二级缓存中删掉 persionA对象,放到一级缓存里 | |
总结:这时,persionA 对象的 pb 属性不为空,pb 属性的 pa 属性也不为空;一级缓存包含 persionA 和 persionB |
RootBeanDefinition(Pojo); < bean/> 有继承的能力(< bean parent=""/> ),因此 Spring 会进行对父子 < bean/> 进行合并操做,最后合并成 RootBeanDefinition 实例,区别于 GenericBeanDefinition 实例 。
代码示例 重要成员变量
public class RootBeanDefinition extends AbstractBeanDefinition { // beanClass 表示 <bean class="org.springframework.PersionA"/> 中的 class 值,一开始为"org.springframework.PersionA"字符串,而后会解析为 PersionA Class 对象,再 set 到当前属性里 private volatile Object beanClass; // 继承自 AbstractBeanDefinition // propertyValues 表示对应 < property/> 信息的实体类 private MutablePropertyValues propertyValues; // scope 表示 <bean/> 的单例模式;scope 默认为"",当 Spring 发现值是空字符串时,而且用户没有指定,就会将值修改成"singleton"(单例),也就是说 Spring 的 <bean/> 默认是单例的。 private String scope = "";
MutablePropertyValues(Pojo),在 Spring 中,用于封装 < property/> 信息的实体类。
代码示例 重要成员变量
public class MutablePropertyValues implements PropertyValues, Serializable { // propertyValueList 表示 <property/> 集合(集合中的一个元素对应一个<property/>标签) private final List<PropertyValue> propertyValueList;
PropertyValue(Pojo),在 Spring 中,对应 < property/> 的实体类,保存了 < property/> 的配置信息,好比属性名、属性值等;这里 Spring 之因此不使用 Map 这种键值对类,是由于自定义类有更强的扩展性。
代码示例 重要成员变量
public class PropertyValue extends BeanMetadataAttributeAccessor implements Serializable { // name 表示 <property/> 中的 name 属性 private final String name; // value 表示 <property/> 指定的值;例:<property name="persionB" ref="pB">,value一开始为指代 ref 的 RuntimeBeanReference 对象;后续逻辑将 RuntimeBeanReference 对象解析为 PersionB 对象,从新覆盖到 value 属性上 private final Object value; // source 是 PropertyValue 实例;在将 RuntimeBeanReference 对象解析为 PersionB对象以前和以后,分别会使用两个 PropertyValue 对象去装载,这个 source 属性就是以前的 PropertyValue 对象(例:<property name="persionB" ref="pB">) private Object source; // conversionNecessary 表示是否转换 <Property/> 指定的值,默认为空(表示有必要进行转换),Spring就会查找用户自定义的转换器进行转换,当发现没有转换器,就会将 conversionNecessary 设置为 false ,不须要转换 volatile Boolean conversionNecessary;
RuntimeBeanReference(Pojo),在 Spring 中,用于装载 < property ref=""/> 中 ref 指定的值。
代码示例 重要成员变量
public class RuntimeBeanReference implements BeanReference { // beanName 表示 ref 的值 private final String beanName;
BeanWrapperImpl(Bo),持有目标对象(例:PersionA 对象),能够对其设置/获取属性的描述信息,好比:查询只读/可写属性等。”企业应用 Demo”中,主要负责给 < bean/> 实例化后的目标对象(例:PersionA 对象)注入的 < property/> 所配置的值。
代码示例 重要成员变量
public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper { // 继承自 AbstractNestablePropertyAccessor // wrappedObject 表示 <bean/> 所表明的目标对象,例:PersionA 对象 Object wrappedObject; // 私有类 // BeanPropertyHandler 表示通用属性描述器,用于保存 < property/> 中的相关信息(例:属性所属类 Class 、属性对应 get/set 方法 Method 对象等);”企业应用 Demo”中,主要用于从本对象获取相应属性的set方法 Method 对象 private class BeanPropertyHandler extends PropertyHandler{...}
BeanWrapperImpl$BeanPropertyHandler(Bo)($ 表示 BeanPropertyHandler 是 BeanWrapperImpl 中的内部类),Bean属性处理器,负责管理 < property/> 属性;”企业应用 Demo”中,主要负责利用反射,调用 setter 方法,对 < bean/> 设置 < property /> 指定的值。
代码示例 重要成员变量
public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements BeanWrapper { private class BeanPropertyHandler extends PropertyHandler { // GenericTypeAwarePropertyDescriptor 实例,继承自 PropertyDescriptor(来自第三方jar包),能够得到类的信息,比 setter 方法、setter 方法的参数类型等 private final PropertyDescriptor pd;
GenericTypeAwarePropertyDescriptor(Pojo), 通用属性描述器,用于保存 < property/> 中的相关信息(例:属性所属类 Class 、属性的对应 get/set 方法 Method 对象等);”企业应用 Demo”中,主要用于从本对象获取相应属性的 set 方法 Method 对象。
代码示例 重要成员变量
final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor { // beanClass 表示 <property/> 的所属类的 Class 对象(例:PersionA.Class) private final Class<?> beanClass; // 继承自 PropertyDescriptor(第三方jar) // writeMethodRef 记录了 <bean/> 对象(例:PersionA )的 set<property/> 的 Method 对象,用于获取 set 方法反射设置属性值 private final MethodRef writeMethodRef = new MethodRef(); // writeMethod 表示 setter 方法的 Method 对象 private final Method writeMethod; // propertyType 表示 <property/> 指代值的 Class 对象 private Class<?> propertyType;
<br/>
加入个人粉丝社群,阅读所有内容
从学习到面试,从面试到工做,从 coder 到 TeamLeader,天天给你答疑解惑,还能有第二份收入,这样的知识星球,难道你还要犹豫!