- 👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主
- 📕系列专栏:Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙、Spring从成神到升仙系列
- 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
- 🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人
- 📝联系方式:hls1793929520,和大家一起学习,一起进步👀
对于Java开发者而言,关于 Spring ,我们一般当做黑盒来进行使用,不需要去打开这个黑盒。
但随着目前程序员行业的发展,我们有必要打开这个黑盒,去探索其中的奥妙。
本期 Spring 源码解析系列文章,将带你领略 Spring 源码的奥秘
本期源码文章吸收了之前 Kafka 源码文章的错误,将不再一行一行的带大家分析源码,我们将一些不重要的部分当做黑盒处理,以便我们更快、更有效的阅读源码。
废话不多说,发车!
本文流程图可关注公众号:爱敲代码的小黄,回复:IOC 获取
贴心的小黄为大家准备的文件格式为 POS文件,方便大家直接导入 ProcessOn 修改使用
首先,我们要引入 Spring 的依赖,这里是用的 4.3.11.RELEASE 版本的,不同的版本源码较有差异,但整体业务逻辑不变
这里讲个小细节,如果你在面试,这里一定要提前给面试官说好你阅读的源码版本,有三方面好处:
第一:避免不同版本的Spring源码不一致导致和面试官的分歧问题
第二:让面试官感觉你小子是真的阅读过源码,就算你说的逻辑和面试官有分歧,面试官第一反应会是源码版本差异导致的
第三:装逼使用…
org.springframework spring-context 4.3.11.RELEASE
创建接口 MessageService:
public interface MessageService { String getMessage(); }
实现类 MessageServiceImpl :
public class MessageServiceImpl implements MessageService { public String getMessage() { return "hello world"; } }
配置文件 application.xml
启动类 SpringStart:
public class SpringStart { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); System.out.println("context 启动成功"); MessageService messageService = context.getBean(MessageService.class); // 输出: hello world System.out.println(messageService.getMessage()); } }
最终输出结果:
context 启动成功 hello world
通过上述代码,我们可以看到,Spring 的 IOC 完全代替了我们之前的 new 的功能,将创建实例交由 Spring 来管理。
那 Spring 是如何管理的呢?源码背后又有什么小技巧呢?今天我们一起来看一下 IOC 源码的解析
为了阅读性,我们将以 xml 文件的配置来阅读源码
首先,我们从 ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); 这一行入手,看其到底执行了什么
我们 debug 点进去可以看到共分为了三部分:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent){ super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
简单来说,这三部分的作为分别是:
我们一起来看一下 refresh 到底做了什么
**整体简介:**做容器刷新前的准备工作
这个方法不重要,也不必要去深入了解,知道做了容器刷新的准备工作即可。
**整体简介:**创建容器,并且完成配置文件的加载
重要的来了,这个方法是比较重要的,一定要记住
首先该方法分为了以下几部分:
protected final void refreshBeanFactory() throws BeansException { // 创建 BeanFactory,类型为 DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } }
上述我们必须记住这个工厂类:DefaultListableBeanFactory,甚至要做到背诵+默写的程度
其次,最重要的就属 loadBeanDefinitions(beanFactory) 方法了
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory){ // 创建XmlBeanDefinitionReader,这个是我们xml文件的解析器 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); initBeanDefinitionReader(beanDefinitionReader); // 加载BeanDefinitions loadBeanDefinitions(beanDefinitionReader); }
我们继续深入看其做了什么
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { // 拿到xml文件的地址 Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
继续往下看,一直到 loadBeanDefinitions
public int loadBeanDefinitions(String location, SetactualResources){ ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader instanceof ResourcePatternResolver) { try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); // 直接看这行,其余不重要 int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } return loadCount; } } else { Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } return loadCount; } }
XmlBeanDefinitionReader 第 388 行
// 将路径封装成一个DOC格式 Document doc = doLoadDocument(inputSource, resource); // 继续注册 return registerBeanDefinitions(doc, resource);
XmlBeanDefinitionReader 第 505 行
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); // 其余不重要,直接看这行 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; // 获取根节点 Element root = doc.getDocumentElement(); // 从根节点开始解析遍历 doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); } } preProcessXml(root); // 直接看这里,其余不重要 parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { // 直接看这里 parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } // 根据不同的配置走不同的分支,配置:import、alias、bean、beans private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
我们这里只看 bean 的配置,其余的读者有兴趣可以自己去 debug 下
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 解析各种xml标签去生成对应的BeanDefinition,读者有兴趣可以自己看一下 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // 重点:正式开始注册 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } } public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) { // 重点,开始注册 String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 注册别名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } } public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) { // 看一下原来的beanDefinitionMap是不是已经有该 beanName 了 // 如果已经存在,我们要排抛出异常(Spring不允许覆盖) BeanDefinition oldBeanDefinition = this.beanDefinitionMap beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException() } } if (oldBeanDefinition != null) { this.beanDefinitionMap.put(beanName, beanDefinition); }else { // 重点在这:将我们的beanName与beanDefinition放至beanDefinitionMap中 this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } }
到这里,基本就结束了,我们来回顾一下 refreshBeanFactory 的业务:
这里可能有人会说,小黄小黄,按你之前解析 kafka 的套路,肯定会分析 beanDefinition 的形成的,现在怎么偷懒不分析了,是不是看不懂~
答:之前分享的 kafka 系列的文章,大家都知道分享的很细,但是我们细细品味一下,我们读源码到底为了什么,以及如何去读、如何有效的读、如何快速的读,我相信每一个人心中都有一套读源码的方式。至于哪一种阅读方式更为合理,后面博主准备单独出一篇文章来讲解,或者你可以私信我,告知我你的读源码的方式,一起加油、一起学习。
整体简介: beanFactory 的准备工作,对各种属性进行填充
这个方法不重要,也不必要去深入了解,知道做了 beanFactory 的填充即可
不过,这里记住,beanFactory 的类一定要记清楚,是 DefaultListableBeanFactory ,不多说直接 背诵+默写
整体简介: 默认没有实现,留给子类进行实现操作
整体简介: 可以自由扩展,通过实现BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 接口,对 beanFactory 里面的 BeanDefinition 进行修改
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 找到当前 beanDefinitionMap 中`BeanFactoryPostProcessor` 和 `BeanDefinitionRegistryPostProcessor`接口的实现 // 若这些实现有对应的order(顺序),则排序之后依次调用 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
温馨小提示:这里有的小伙伴可能对 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 接口不熟悉,我们将此处的讲解放至:附录2
整体简介: 完成 spring 自带或者用户自定义的 BeanPostProcessor 的解析
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 实例化并且注册所有的beanPostProcessor PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); }
这里的操作实际上和我们上面 invokeBeanFactoryPostProcessors 里面很像,都是对实现一些特定接口的类做加载,但需要注意的是:对于实现 BeanPostProcessor 接口的来说,我们不会在此立即调用,会在 Bean 初始化方法前后调用。
对了,提前剧透一下,我们响当当的 AOP 也是在这里实现的,后续我们也会讲的。
温馨小提示:这里有的小伙伴可能对 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 接口不熟悉,我们将此处的讲解放至:附录3
整体简介: Spring 中国际化的功能
整体简介: 初始化事件广播器
整体简介: 在 spring 中默认没有任何实现,模板方法,但是在 springboot 中启动了 web 容器
整体简介: 注册监听器,为了方便接受广播的事件
整体简介:完成所有非懒加载的单例对象的实例化操作,从此方法开始进行对象的创建,包含了实例化,初始化,循环依赖,AOP等核心逻辑的处理过程,此步骤是最最核心且关键的点,要对其中的细节最够清楚
由于篇幅原因,博主会尽量挑选一些重要的地方进行分析。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // 实例化剩下的单例对象 beanFactory.preInstantiateSingletons(); } public void preInstantiateSingletons(){ // 拿到我们之前存储的所有beanDefinition的名字 ListbeanNames = new ArrayList<>(this.beanDefinitionNames); // 触发单例bean的初始化,遍历集合的对象 for (String beanName : beanNames) { // 如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例 getBean(beanName); } } public Object getBean(String name) throws BeansException { // 此方法是实际获取bean的方法,也是触发依赖注入的方法 return doGetBean(name, null, null, false); } protected T doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly){ // 这里需要一步转换,这里的原因我们附录1提到过,这里不再过多讨论 String beanName = transformedBeanName(name); // 提前检查单例缓存中是否有手动注册的单例对象,剧透一下(和循环依赖有关联) Object sharedInstance = getSingleton(beanName); // 当对象都是单例的时候会尝试解决循环依赖的问题,但是原型模式下如果存在循环依赖的情况,那么直接抛出异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } if (mbd.isSingleton()) { // 返回以beanName的(原始)单例对象,如果尚未注册,则使用singletonFactory创建并注册一个对象: sharedInstance = getSingleton(beanName, () -> { try { // 为给定的合并后BeanDefinition(和参数)创建一个bean实例 // 这也是我们的核心方法 return createBean(beanName, mbd, args); } }); } protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){ // 实际创建bean的调用 Object beanInstance = doCreateBean(beanName, mbdToUse, args); } protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){ // 根据执行bean使用对应的策略创建新的实例,如,工厂方法,构造函数主动注入、简单初始化 BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); // 对bean的属性进行填充,将各个属性值注入,其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean populateBean(beanName, mbd, instanceWrapper); // 执行初始化逻辑 exposedObject = initializeBean(beanName, exposedObject, mbd); }
到这里我们先停一停,我们总结一下创建实例的一些步骤:
拿到我们之前注册的 beanDefinitionNames,遍历整个 beanDefinitionNames,每一个 BeanName 生成一个对象
我们需要进行名称转化,防止传入的是一个别名或其他的名称,利用转换后的别名去调用
查询我们的单例缓存中是否已经存在该实例,如果存在直接返回即可
如果不存在,则需要去根据该 beanDefinition 去生成对应的实例
对于生成实例共有三个步骤:
我们对于每个步骤都进行分析:
对于实例创建,Spring 中创建 bean 的方式大致可分为三种:
可能大家有点懵,怎么这么多创建的方法,这里其实我们不需要太过于关注,只需要关注 类名称 + 自定义 beanName 这种方法即可,其余两种基本很少用到
对于 类名称 + 自定义 beanName 我们一般有两种构造方法:
为了便于理解,我们这里只介绍无参构造
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { // 根据当前的beanName拿到其 Class Class> beanClass = resolveBeanClass(mbd, beanName); // 前面的有参都不存在,则进行无参构造 return instantiateBean(beanName, mbd); } protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) { // 获取实例化策略并且进行实例化操作 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this); } public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // 锁一下对象,线程安全 synchronized (bd.constructorArgumentLock) { // 得到当前bean的Class Class> clazz = bd.getBeanClass(); // 通过class得到其默认的构造方法 constructorToUse = clazz.getDeclaredConstructor(); // return BeanUtils.instantiateClass(constructorToUse); } } public staticT instantiateClass(Constructor ctor, Object... args) { // 构造方法+入参 // 如果当前是无参构造方法的话,则argsWithDefaultValues为空 return ctor.newInstance(argsWithDefaultValues); }
总结一下通过无参构造创建实例的步骤:
其实有参的构造方法也类似,只不过相较于无参构造,反射传入的 argsWithDefaultValues 的参数,这里的参数可以为 Bean 也可以为数值,所以这里也会出现循环依赖的问题。
属性填充相对简单,流程我们大致过一下,属性注入类似:
其中的 property 标签就是我们的属性值。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { // 得到当前 BeanDefinition 的属性值 PropertyValues pvs = mbd.getPropertyValues(); if (pvs != null) { // 注入属性 applyPropertyValues(beanName, mbd, bw, pvs); } } protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs){ // 获取pvs的PropertyValue对象数组,并将其转换成列表 Listoriginal = Arrays.asList(pvs.getPropertyValues()); for (PropertyValue pv : original) { // 获取属性的名字 String propertyName = pv.getName(); // 获取未经类型转换的值 Object originalValue = pv.getValue(); // 这里需要进行一系列的转换 // 因为我们的属性注入有可能注入的是一个BeanReference,需要重新去 BeanFactory 中获取实例 // 转换后的放至 deepCopy // 按原样使用deepCopy构造一个新的MutablePropertyValues对象然后设置到bw中以对bw的属性值更新 bw.setPropertyValues(new MutablePropertyValues(deepCopy)); } } public void setPropertyValues(PropertyValues pvs){ setPropertyValues(pvs, false, false); } public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid){ // 后续主要通过反射对值进行设置,感兴趣的可以自己去看下源码实现 setPropertyValue(pv); }
我们这里先实现一个 BeanPostProcessor 接口,便于我们的观察:
public class MyTest implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("我前置增强"); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("我后置增强"); return bean; } }
直接看我们的源码:
// 执行初始化逻辑 exposedObject = initializeBean(beanName, exposedObject, mbd); protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { // 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessBeforeInitialization初始化方法。 // 返回的Bean实例可能是原始Bean包装器 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法 invokeInitMethods(beanName, wrappedBean, mbd); // 将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。 // 返回的Bean实例可能是原始Bean包装器 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); //返回包装后的Bean return wrappedBean; } // 执行所有的BeanPostProcessors接口下的类 // 如果我们自己实现的类对 Bean 进行了包装,比如AOP,则使用我们实现类里面返回的 public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName){ Object result = existingBean; //遍历 该工厂创建的bean的BeanPostProcessors列表 for (BeanPostProcessor processor : getBeanPostProcessors()) { // 默认实现按原样返回给定的 Bean Object current = processor.postProcessBeforeInitialization(result, beanName); // 如果 current为null if (current == null) { //直接返回result,中断其后续的BeanPostProcessor处理 return result; } //让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装 result = current; } //返回经过所有BeanPostProcess对象的后置处理的层层包装后的result return result; } protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd){ // 如果mbd不为null&&bean不是NullBean类 if (mbd != null && bean.getClass() != NullBean.class) { // 获取mbd指定的初始化方法名 String initMethodName = mbd.getInitMethodName(); // 在bean上调用指定的自定义init方法 invokeCustomInitMethod(beanName, bean, mbd); // 具体调用,反射执行 // Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod); // methodToInvoke.invoke(bean); } } // 执行所有的BeanPostProcessors接口下的类 // 如果我们自己实现的类对 Bean 进行了包装,比如AOP,则使用我们实现类里面返回的 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName){ //初始化结果对象为result,默认引用existingBean Object result = existingBean; //遍历该工厂创建的bean的BeanPostProcessors列表 for (BeanPostProcessor processor : getBeanPostProcessors()) { //回调BeanPostProcessor#postProcessAfterInitialization来对现有的bean实例进行包装 Object current = processor.postProcessAfterInitialization(result, beanName); // 如果current为null if (current == null) { //直接返回result,中断其后续的BeanPostProcessor处理 return result; } //让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装 result = current; } //返回经过所有BeanPostProcess对象的后置处理的层层包装后的result return result; }
其实初始化的逻辑也很简单,就是调用我们的 BeanPostProcess 实现扩展点的应用
然后初始化 init 方法即可
整体简介: 完成整个容器的启动,所有的对象都准备完成,可以进行后续业务流程的操作,清除上下文缓存,初始化生命周期处理器,发送刷新完成事件
前面我们已经创建成功了对象,当我们使用完成之后,肯定要进行销毁,那么 Spring 是如何做的销毁对象的管理呢
执行 context.close(); 方法:
public void close() { synchronized (this.startupShutdownMonitor) { doClose(); } } protected void doClose() { // 清空 DefaultListableBeanFactory 里面的缓存 destroyBeans(); // 直接将beanFactory置为null closeBeanFactory(); } protected void destroyBeans() { // 清空在包含的Bean名称之间映射:bean名称-Bean包含的Bean名称集 this.containedBeanMap.clear(); // 清空在相关的Bean名称之间映射:bean名称-一组相关的Bean名称 this.dependentBeanMap.clear(); // 清空在相关的Bean名称之j键映射:bean名称bean依赖项的Bean名称集 this.dependenciesForBeanMap.clear(); // 清除此注册表中所有缓存的单例实例 clearSingletonCache(); } protected void clearSingletonCache() { // 加锁,使用单例对象的高速缓存:beam名称-bean实例作为锁 synchronized (this.singletonObjects) { // 清空单例对象的高速缓存:beam名称-bean实例 this.singletonObjects.clear(); // 清空单例工厂的缓存:bean名称-ObjectFactory this.singletonFactories.clear(); // 清空早期单例对象的高速缓存:bean名称-bean实例 this.earlySingletonObjects.clear(); // 清空已注册的单例集,按照注册顺序包含bean名称 this.registeredSingletons.clear(); // 设置当前是否在destroySingletons中的标志为false this.singletonsCurrentlyInDestruction = false; } } private void clearByTypeCache() { this.allBeanNamesByType.clear(); this.singletonBeanNamesByType.clear(); } // 直接将beanFactory置空 protected final void closeBeanFactory() { DefaultListableBeanFactory beanFactory = this.beanFactory; if (beanFactory != null) { beanFactory.setSerializationId(null); this.beanFactory = null; } }
这基本就是销毁的整个流程。
这里还有一个小知识点,就是我们可以自定义我们的销毁方法,比如如下:
public class MessageServiceImpl implements MessageService { public String getMessage() { return "hello world"; } public void init(){ System.out.println("我是类的初始化"); } public void destroy(){ System.out.println("我是类的销毁"); } }
在执行 context.close(); 方法时,会调用该 Bean 的销毁方法,至于怎么调用的。
这里交给读者了(真不是我懒
又是一篇大工程的文章结束了
记得校招时候,当时对 Spring 懵懂无知,转眼间也被迫看了源码
有些小伙伴可能疑惑:哎,博主,你这不对呀,你这循环依赖也没讲、三级缓存也没讲,你是不是漏的有点多。
因为咱们这篇文章主要针对的是 Spring IOC 的源码,对于三级缓存、循环依赖来说,主要解决 AOP 代理对象的问题,这个我们后面单独出一篇来描述,不要着急,小黄不会不讲的。
当然,本篇只介绍了 XML 配置,如果你对注解的配置感兴趣的话,也可以去看一下 AnnotationConfigApplicationContext 的流程,区别不大,一个是解析的 xml,一个是解析的注解
但通过这篇文章,我相信,99% 的人应该都可以理解了 Spring IOC 的来龙去脉
那么如何证明你真的理解了 Spring IOC 呢,我这里出个经典的题目,大家可以想一下:Bean 的生命周期
如果你能看到这,那博主必须要给你一个大大的鼓励,谢谢你的支持!
喜欢的可以点个关注,后续会更新 Spring 源码系列文章
我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,Java领域新星创作者,喜欢后端架构和中间件源码。
我们下期再见。
当我们使用 GetBean(beanName) 时,Spring会默认其是别名,并进行循环获取
protectedT doGetBean(String name){ final String beanName = transformedBeanName(name); } protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } public String canonicalName(String name) { String canonicalName = name; String resolvedName; do { resolvedName = (String)this.aliasMap.get(canonicalName); if (resolvedName != null) { canonicalName = resolvedName; } } while(resolvedName != null); return canonicalName; }
这两个类的作用主要对我们 BeanFactory 的 BeanDefinitions 进行修改,举个例子:
public class MyTest implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 拿到我们 id = messageService 的 PropertyValue MutablePropertyValues messageService = beanFactory.getBeanDefinition("messageService").getPropertyValues(); ListpropertyValueList = messageService.getPropertyValueList(); // 遍历输出,当然也可以进行修改 for (PropertyValue propertyValue : propertyValueList) { System.out.println("BeanFactoryPostProcessor : name = " + propertyValue.getName() + " value = " + propertyValue.getValue()); } } }
我们看一下启动的效果:
BeanFactoryPostProcessor : name = name value = TypedStringValue: value [hls], target type [null]
这两个类主要是扩展进行使用,比如我们的 AOP 或者其他的扩展点,举个例子:
public class MyTest implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("我会在类初始化前调用"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("我会在类初始化后调用"); return bean; } }
我们看一下启动的效果:
我会在类初始化前调用 我是类的初始化 我会在类初始化后调用