酒店设计的网站建设博客网站是自己做的吗

当前位置: 首页 > news >正文

酒店设计的网站建设,博客网站是自己做的吗,网站托管网站建设竞价托管,苏州刚刚发生新闻#x1f44f;作者简介#xff1a;大家好#xff0c;我是爱敲代码的小黄#xff0c;独角兽企业的Java开发工程师#xff0c;CSDN博客专家#xff0c;阿里云专家博主#x1f4d5;系列专栏#xff1a;Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙… 作者简介大家好我是爱敲代码的小黄独角兽企业的Java开发工程师CSDN博客专家阿里云专家博主系列专栏Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙、Spring从成神到升仙系列如果感觉博主的文章还不错的话请三连支持一下博主哦博主正在努力完成2023计划中以梦为马扬帆起航2023追梦人联系方式hls1793929520和大家一起学习一起进步 文章目录Spring IOC源码解析一、引言二、Spring启动配置三、IOC 源码剖析1、prepareRefresh2、obtainFreshBeanFactory2.1 refreshBeanFactory3、prepareBeanFactory4、postProcessBeanFactory5、invokeBeanFactoryPostProcessors6、registerBeanPostProcessors7、initMessageSource8、initApplicationEventMulticaster9、onRefresh10、registerListeners11、finishBeanFactoryInitialization11.1 创建实例11.2 属性填充11.3 初始化逻辑12、finishRefresh13、销毁五、流程图六、总结七、附录1、注册别名的原因2、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor3、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessorSpring IOC源码解析 一、引言 对于Java开发者而言关于 Spring 我们一般当做黑盒来进行使用不需要去打开这个黑盒。 但随着目前程序员行业的发展我们有必要打开这个黑盒去探索其中的奥妙。 本期 Spring 源码解析系列文章将带你领略 Spring 源码的奥秘 本期源码文章吸收了之前 Kafka 源码文章的错误将不再一行一行的带大家分析源码我们将一些不重要的部分当做黑盒处理以便我们更快、更有效的阅读源码。 废话不多说发车 本文流程图可关注公众号爱敲代码的小黄回复IOC 获取 贴心的小黄为大家准备的文件格式为 POS文件方便大家直接导入 ProcessOn 修改使用 二、Spring启动配置 首先我们要引入 Spring 的依赖这里是用的 4.3.11.RELEASE 版本的不同的版本源码较有差异但整体业务逻辑不变 这里讲个小细节如果你在面试这里一定要提前给面试官说好你阅读的源码版本有三方面好处 第一避免不同版本的Spring源码不一致导致和面试官的分歧问题 第二让面试官感觉你小子是真的阅读过源码就算你说的逻辑和面试官有分歧面试官第一反应会是源码版本差异导致的 第三装逼使用… dependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion4.3.11.RELEASE/version /dependency创建接口 MessageService public interface MessageService {String getMessage(); }实现类 MessageServiceImpl
public class MessageServiceImpl implements MessageService {public String getMessage() {return hello world;} }配置文件 application.xml ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdbean idmessageService classcn.hls.spring.MessageServiceImpl/ /beans启动类 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 worldSystem.out.println(messageService.getMessage());} }最终输出结果 context 启动成功 hello world通过上述代码我们可以看到Spring 的 IOC 完全代替了我们之前的 new 的功能将创建实例交由 Spring 来管理。 三、IOC 源码剖析 那 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();} }简单来说这三部分的作为分别是 super(parent)调用父类的构造方法创建 PathMathingResourcePatternResolver 解析配置文件setConfigLocations(configLocations)设置 configLocations(配置文件路径) 到当前应用程序中refresh()解析配置文件、完成bean的注册、实例化、初始化、代理等一系列的工作最终创建出一个 Bean 实例 我们一起来看一下 refresh 到底做了什么 1、prepareRefresh 整体简介做容器刷新前的准备工作 设置容器的启动时间this.startupDate System.currentTimeMillis();设置活跃状态为 trueactive.set(true)设置关闭状态为 falseclosed.set(false)获取 Environment 对象并加载当前系统的属性值到 Environment 对象中准备监听器和事件的集合对象默认为空的集合earlyApplicationEvents new LinkedHashSetApplicationEvent(); 这个方法不重要也不必要去深入了解知道做了容器刷新的准备工作即可。 2、obtainFreshBeanFactory 整体简介创建容器并且完成配置文件的加载 重要的来了这个方法是比较重要的一定要记住 首先该方法分为了以下几部分 refreshBeanFactory解析我们的 application.xml 文件并生成 BeanDefinition 注册至 DefaultListableBeanFactory 的 beanDefinitionMap 中getBeanFactory获取工厂bean 2.1 refreshBeanFactory protected final void refreshBeanFactory() throws BeansException {// 创建 BeanFactory类型为 DefaultListableBeanFactoryDefaultListableBeanFactory 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);// 加载BeanDefinitionsloadBeanDefinitions(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, SetResource actualResources){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)) {// recursedoRegisterBeanDefinitions(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 的业务 通过我们传递的xml 文件的路径利用 documentLoader 将其封装成 Document 格式创建 BeanDefinitionDocumentReader 来正式解析 xml 文件并找到文件的 root根据 root 扫描遍历对不同配置的标签import、alias、bean、beans走不同的逻辑判断将当前的标签各属性进行组装成 beanDefinition调用 DefaultListableBeanFactory 进行注册根据 BeanName 查询该 beanDefinition 是否被注册过如果被注册过则直接抛出异常Spring不允许覆盖如果没有注册过则将 BeanName 与 beanDefinition 注册至 DefaultListableBeanFactory 的 beanDefinitionMap 中最后如果该 beanDefinition 含有别名也要将别名进行注册至于为什么注册别名可见附录1 这里可能有人会说小黄小黄按你之前解析 kafka 的套路肯定会分析 beanDefinition 的形成的现在怎么偷懒不分析了是不是看不懂~ 答之前分享的 kafka 系列的文章大家都知道分享的很细但是我们细细品味一下我们读源码到底为了什么以及如何去读、如何有效的读、如何快速的读我相信每一个人心中都有一套读源码的方式。至于哪一种阅读方式更为合理后面博主准备单独出一篇文章来讲解或者你可以私信我告知我你的读源码的方式一起加油、一起学习。 3、prepareBeanFactory 整体简介 beanFactory 的准备工作对各种属性进行填充 这个方法不重要也不必要去深入了解知道做了 beanFactory 的填充即可 不过这里记住beanFactory 的类一定要记清楚是 DefaultListableBeanFactory 不多说直接 背诵默写 4、postProcessBeanFactory 整体简介 默认没有实现留给子类进行实现操作 5、invokeBeanFactoryPostProcessors 整体简介 可以自由扩展通过实现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 6、registerBeanPostProcessors 整体简介 完成 spring 自带或者用户自定义的 BeanPostProcessor 的解析 protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {// 实例化并且注册所有的beanPostProcessorPostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); }这里的操作实际上和我们上面 invokeBeanFactoryPostProcessors 里面很像都是对实现一些特定接口的类做加载但需要注意的是对于实现 BeanPostProcessor 接口的来说我们不会在此立即调用会在 Bean 初始化方法前后调用。 对了提前剧透一下我们响当当的 AOP 也是在这里实现的后续我们也会讲的。 温馨小提示这里有的小伙伴可能对 BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 接口不熟悉我们将此处的讲解放至附录3 7、initMessageSource 整体简介 Spring 中国际化的功能 8、initApplicationEventMulticaster 整体简介 初始化事件广播器 9、onRefresh 整体简介 在 spring 中默认没有任何实现模板方法但是在 springboot 中启动了 web 容器 10、registerListeners 整体简介 注册监听器为了方便接受广播的事件 11、finishBeanFactoryInitialization 整体简介完成所有非懒加载的单例对象的实例化操作从此方法开始进行对象的创建包含了实例化初始化循环依赖AOP等核心逻辑的处理过程此步骤是最最核心且关键的点要对其中的细节最够清楚 由于篇幅原因博主会尽量挑选一些重要的地方进行分析。 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 实例化剩下的单例对象beanFactory.preInstantiateSingletons(); }public void preInstantiateSingletons(){// 拿到我们之前存储的所有beanDefinition的名字ListString beanNames 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 T doGetBean(String name, Nullable ClassT 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的属性则会递归初始化依赖的beanpopulateBean(beanName, mbd, instanceWrapper);// 执行初始化逻辑exposedObject initializeBean(beanName, exposedObject, mbd); }到这里我们先停一停我们总结一下创建实例的一些步骤 拿到我们之前注册的 beanDefinitionNames遍历整个 beanDefinitionNames每一个 BeanName 生成一个对象 我们需要进行名称转化防止传入的是一个别名或其他的名称利用转换后的别名去调用 查询我们的单例缓存中是否已经存在该实例如果存在直接返回即可 如果不存在则需要去根据该 beanDefinition 去生成对应的实例 对于生成实例共有三个步骤 创建实例属性填充初始化逻辑 实现 BeanPostProcessor 的前置方法对象的初始化方法实现 BeanPostProcessor 的后置方法
我们对于每个步骤都进行分析 11.1 创建实例 对于实例创建Spring 中创建 bean 的方式大致可分为三种 类名称 自定义 beanName工厂类名称 自定义工厂静态方法 自定义 beanName提前注册工厂bean使用工厂bean 工厂方法自定义 beanName 可能大家有点懵怎么这么多创建的方法这里其实我们不需要太过于关注只需要关注 类名称 自定义 beanName 这种方法即可其余两种基本很少用到 对于 类名称 自定义 beanName 我们一般有两种构造方法 无参构造常用有参构造不常用 为了便于理解我们这里只介绍无参构造 BeanWrapper instanceWrapper createBeanInstance(beanName, mbd, args);protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {// 根据当前的beanName拿到其 ClassClass? 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的ClassClass? clazz bd.getBeanClass();// 通过class得到其默认的构造方法constructorToUse clazz.getDeclaredConstructor();// return BeanUtils.instantiateClass(constructorToUse);} }public static T T instantiateClass(ConstructorT ctor, Object… args) {// 构造方法入参// 如果当前是无参构造方法的话则argsWithDefaultValues为空return ctor.newInstance(argsWithDefaultValues); }总结一下通过无参构造创建实例的步骤 加锁保证线程安全得到当前 bean 的 Class通过其 Class 得到默认的无参构造方法通过反射直接创建即可 其实有参的构造方法也类似只不过相较于无参构造反射传入的 argsWithDefaultValues 的参数这里的参数可以为 Bean 也可以为数值所以这里也会出现循环依赖的问题。 11.2 属性填充 属性填充相对简单流程我们大致过一下属性注入类似 bean idmessageService classcom.mashibing.hls.MessageServiceImplproperty namename valuehls/ /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对象数组并将其转换成列表ListPropertyValue original 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); }11.3 初始化逻辑 我们这里先实现一个 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);//返回包装后的Beanreturn wrappedBean; }// 执行所有的BeanPostProcessors接口下的类 // 如果我们自己实现的类对 Bean 进行了包装比如AOP则使用我们实现类里面返回的 public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName){Object result existingBean;//遍历 该工厂创建的bean的BeanPostProcessors列表for (BeanPostProcessor processor : getBeanPostProcessors()) {// 默认实现按原样返回给定的 BeanObject current processor.postProcessBeforeInitialization(result, beanName);// 如果 current为nullif (current null) {//直接返回result中断其后续的BeanPostProcessor处理return result;}//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装result current;}//返回经过所有BeanPostProcess对象的后置处理的层层包装后的resultreturn result; }protected void invokeInitMethods(String beanName, Object bean, Nullable RootBeanDefinition mbd){// 如果mbd不为nullbean不是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默认引用existingBeanObject result existingBean;//遍历该工厂创建的bean的BeanPostProcessors列表for (BeanPostProcessor processor : getBeanPostProcessors()) {//回调BeanPostProcessor#postProcessAfterInitialization来对现有的bean实例进行包装Object current processor.postProcessAfterInitialization(result, beanName);// 如果current为nullif (current null) {//直接返回result中断其后续的BeanPostProcessor处理return result;}//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装result current;}//返回经过所有BeanPostProcess对象的后置处理的层层包装后的resultreturn result;}其实初始化的逻辑也很简单就是调用我们的 BeanPostProcess 实现扩展点的应用 然后初始化 init 方法即可 12、finishRefresh 整体简介 完成整个容器的启动所有的对象都准备完成可以进行后续业务流程的操作清除上下文缓存初始化生命周期处理器发送刷新完成事件 13、销毁 前面我们已经创建成功了对象当我们使用完成之后肯定要进行销毁那么 Spring 是如何做的销毁对象的管理呢 执行 context.close(); 方法 public void close() {synchronized (this.startupShutdownMonitor) {doClose();} }protected void doClose() {// 清空 DefaultListableBeanFactory 里面的缓存destroyBeans();// 直接将beanFactory置为nullcloseBeanFactory(); }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名称-ObjectFactorythis.singletonFactories.clear();// 清空早期单例对象的高速缓存bean名称-bean实例this.earlySingletonObjects.clear();// 清空已注册的单例集按照注册顺序包含bean名称this.registeredSingletons.clear();// 设置当前是否在destroySingletons中的标志为falsethis.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;} }这基本就是销毁的整个流程。 这里还有一个小知识点就是我们可以自定义我们的销毁方法比如如下 bean idmessageService classcn.hls.spring.MessageServiceImpl init-methodinit destroy-methoddestroy/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领域新星创作者喜欢后端架构和中间件源码。 我们下期再见。 七、附录 1、注册别名的原因 当我们使用 GetBean(beanName) 时Spring会默认其是别名并进行循环获取 protected T T 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; }2、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 这两个类的作用主要对我们 BeanFactory 的 BeanDefinitions 进行修改举个例子 public class MyTest implements BeanFactoryPostProcessor {Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 拿到我们 id messageService 的 PropertyValueMutablePropertyValues messageService beanFactory.getBeanDefinition(messageService).getPropertyValues();ListPropertyValue propertyValueList 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]3、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 这两个类主要是扩展进行使用比如我们的 AOP 或者其他的扩展点举个例子 public class MyTest implements BeanPostProcessor {Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println(我会在类初始化前调用);return bean;}Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println(我会在类初始化后调用);return bean;} }我们看一下启动的效果 我会在类初始化前调用 我是类的初始化 我会在类初始化后调用