Spring容器系列-启动原理(下)
Spring容器系列-启动原理(下)
从上一篇文章《Spring容器系列-启动原理(上)》中,介绍了Spring容器初始化的核心方法refresh()的整体情况。这篇文章来详细展开介绍。其中比较重要的方法会标记上***
一、refresh中的12个方法
1. prepareRefresh
主要作用:记录下容器启动时间,标记"已启动"状态
2. obtainFreshBeanFactory ***
主要作用:创建bean工厂,如果已经有则销毁,没有则创建。将配置文件解析成一个个 Bean 定义,注册到 BeanFactory中。
里面实现对beanDefinition的装载(说到底核心是一个key为beanName,value为beanDefinition的 map)
1 //用于保存BeanDefinition 2 //key:beanName value:BeanDefinition 3 7 private final Map<string,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
下面根据代码进行说明:
refresh()中通过obtainFreshBeanFactory()去解析 xml 文件,并且创建 BeanFactory(获取到的是DefaultListableBeanFactory类的实例)。
这一步主要看AbstractRefreshableApplicationContext#refreshBeanFactory()中的loadBeanDefinitions()。
1 protected final void refreshBeanFactory() throws BeansException { 2 //如果BeanFactory不为空,则清除BeanFactory和里面的实例 3 if (hasBeanFactory()) { 4 destroyBeans(); 5 closeBeanFactory(); 6 } 7 try { 8 //BeanFactory 实例工厂 9 DefaultListableBeanFactory beanFactory = createBeanFactory(); 10 beanFactory.setSerializationId(getId()); 11 //设置是否可以循环依赖 allowCircularReferences 12 //是否允许使用相同名称重新注册不同的bean实现. 13 customizeBeanFactory(beanFactory); 14 //解析xml,并把xml中的标签封装成BeanDefinition对象 15 loadBeanDefinitions(beanFactory); 16 this.beanFactory = beanFactory; 17 } 18 catch (IOException ex) { 19 throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); 20 } 21 }
3. prepareBeanFactory ***
主要作用:设置BeanFactory的类加载器,添加一些默认的后置处理器,注册默认的系统环境bean:环境配置、系统属性、系统环境变量
说明:上一步 obtainFreshBeanFactory 已经把工厂建好了,但是还不能投入使用,因为工厂里什么都没有,还需要配置一些东西
4. postProcessBeanFactory ***
主要作用:空方法 - 模版方法,由子类重写。让子类有机会在 BeanFactory 准备就绪后对其进行进一步的处理或配置:例如添加自定义的BeanPostProcessor、注册特定类型的Bean等。
说明:这里采用模版方法设计模式,空方法,留给子类来实现
5. invokeBeanFactoryPostProcessors ***
主要作用:在应用上下文中调用所有注册的 BeanFactoryPostProcessor 实现类的 postProcessBeanFactory 方法,以便对 BeanFactory 进行进一步的定制和处理
1 @FunctionalInterface 2 public interface BeanFactoryPostProcessor { 3 void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; 4 5 }
说明:通常情况下,开发者可以通过实现 BeanFactoryPostProcessor 接口,在 postProcessBeanFactory 方法中编写自己的定制逻辑,以满足特定的需求。当调用 invokeBeanFactoryPostProcessors(beanFactory) 方法时,Spring 将自动扫描并调用所有注册的 BeanFactoryPostProcessor 实现类的 postProcessBeanFactory 方法,完成容器的预处理工作。
6. registerBeanPostProcessors ***
主要作用:将自定义的配置文件中的BeanPostProcessor提取出来并注册进入beanFactory
说明:这些后置处理器实现了 BeanPostProcessor 接口,用于在容器中的 Bean 创建、初始化、销毁等生命周期阶段进行特定操作。通过注册后置处理器,可以对容器中的 Bean 进行额外的处理,例如,AOP 切面的织入、自定义注解的处理、事件监听等。
注册后置处理器是 Spring 框架实现灵活性和扩展性的重要手段之一,可以让开发者根据具体需求定制自己的处理逻辑,并将其无缝地集成到 Spring 容器中。
7. initMessageSource
主要作用:初始化消息源,为 Spring 应用程序的国际化功能提供支持
8. initApplicationEventMulticaster
主要作用:初始化事件管理类
事件管理类用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 ApplicationContext 发布的 Event 广播给它的监听器列表。
9. onRefresh
主要作用:模版方法,由子类重写。用于在容器刷新时执行特定的自定义操作:如创建Tomcat,Jetty等WEB服务器
说明:在该方法中,可以添加任何希望在容器刷新完成后执行的逻辑,比如启动定时任务、初始化缓存、加载配置文件等等。通过重写这个方法,可以扩展容器刷新的行为,使得容器更适应特定的应用场景或业务需求。
10. registerListeners
主要作用:注册监听器,将监听器注册到事件管理类中。
11. finishBeanFactoryInitialization ***
主要作用:实例化所有剩余的(非懒加载)的单例 Bean
如下图:
此处只分析实际起作用的DefaultListableBeanFactory#preInstantiateSingletons() 方法。
Spring在实例化的时候会进行判断,只有单例,并且不是LazyInit的Bean才会在初始化过程中创建,其他的比如Prototype或Lazy的只有在使用到时会通过getBean来创建。
下面我们来分析实例化Bean的过程,DefaultListableBeanFactory#preInstantiateSingletons() :
1 @Override 2 public void preInstantiateSingletons() throws BeansException { 3 // 先得到BeanDefinitionMap中已经注册的所有Bean Definition名称 4 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); 5 // 依次遍历所有的名称 6 for (String beanName : beanNames) { 7 // 获取bd(Bean Definition),判断当前bd所代表的类不是Abstract的,也不是需要延迟加载的并且是单例的。 8 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 9 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 10 // 判断当前bd代表的类是否为工厂,此方法内部会调用依次getObject方法,由于Spring自己的类(BeanPostProcessor)在前面注册时已经实例化,故可以直接获取到。而自定义的Bean并不会生成对象,会通过bd来判断是否为工厂Bean,此处先不讨论FactoryBean的情况,先来分析普通Bean 11 if (isFactoryBean(beanName)) { 12 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); 13 if (bean instanceof FactoryBean) { 14 final FactoryBean<?> factory = (FactoryBean<?>) bean; 15 boolean isEagerInit; 16 if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { 17 isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) 18 ((SmartFactoryBean<?>) factory)::isEagerInit, 19 getAccessControlContext()); 20 } 21 else { 22 isEagerInit = (factory instanceof SmartFactoryBean && 23 ((SmartFactoryBean<?>) factory).isEagerInit()); 24 } 25 if (isEagerInit) { 26 getBean(beanName); 27 } 28 } 29 } 30 else { 31 // 这里从ioc容器中获取bean,如果不存在则创建 32 getBean(beanName); 33 } 34 } 35 } 36 }
在preInstantiateSingletons
方法里调用了AbstractBeanFactory
的getBean
方法。最终调用doGetBean()方法,下面我们看AbstractBeanFactory#doGetBean方法:
1 protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { 2 //1.处理bean名称解析 3 String beanName = this.transformedBeanName(name); 4 Object sharedInstance = this.getSingleton(beanName); 5 Object beanInstance; 6 //从单例缓存中判断是否存在这个示例,可能来源于Spring启动的时候,也有可能来源于Spring 启动时初始化了非懒加载的对象 7 if (sharedInstance != null && args == null) { 8 if (this.logger.isTraceEnabled()) { 9 if (this.isSingletonCurrentlyInCreation(beanName)) { 10 this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); 11 } else { 12 this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); 13 } 14 } 15 //如果单例工厂存在这个bean,则通过调用getObject方法获取bean实例 16 beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null); 17 } else { 18 //如果当前线程存在这个实例,则抛出异常 19 if (this.isPrototypeCurrentlyInCreation(beanName)) { 20 throw new BeanCurrentlyInCreationException(beanName); 21 } 22 //2.获取当前bean工厂的父工厂,然后获取bean,此处是递归查找 23 BeanFactory parentBeanFactory = this.getParentBeanFactory(); 24 if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) { 25 String nameToLookup = this.originalBeanName(name); 26 if (parentBeanFactory instanceof AbstractBeanFactory) { 27 28 return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly); 29 } 30 31 if (args != null) { 32 //调用父工厂的getBean方法 33 return parentBeanFactory.getBean(nameToLookup, args); 34 } 35 36 if (requiredType != null) { 37 //根据类型获取bean 38 return parentBeanFactory.getBean(nameToLookup, requiredType); 39 } 40 41 return parentBeanFactory.getBean(nameToLookup); 42 } 43 //如果参数为检查类型,则设置名称为beanName的bean实例已经创建的标识 44 if (!typeCheckOnly) { 45 this.markBeanAsCreated(beanName); 46 } 47 48 StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate").tag("beanName", name); 49 50 try { 51 if (requiredType != null) { 52 beanCreation.tag("beanType", requiredType::toString); 53 } 54 55 RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName); 56 this.checkMergedBeanDefinition(mbd, beanName, args); 57 //3.获取bean的依赖属性 58 String[] dependsOn = mbd.getDependsOn(); 59 String[] var12; 60 if (dependsOn != null) { 61 var12 = dependsOn; 62 int var13 = dependsOn.length; 63 64 for(int var14 = 0; var14 < var13; ++var14) { 65 String dep = var12[var14]; 66 //检查是否存在循环依赖 67 if (this.isDependent(beanName, dep)) { 68 throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); 69 } 70 //向注册器中注册这个依赖的bean 71 this.registerDependentBean(dep, beanName); 72 73 try { 74 //获取并解决当前bean 75 this.getBean(dep); 76 } catch (NoSuchBeanDefinitionException var31) { 77 throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var31); 78 } 79 } 80 } 81 //根据 scope 处理当前bean 82 if (mbd.isSingleton()) { 83 sharedInstance = this.getSingleton(beanName, () -> { 84 try { 85 return this.createBean(beanName, mbd, args); 86 } catch (BeansException var5) { 87 this.destroySingleton(beanName); 88 throw var5; 89 } 90 }); 91 beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 92 } else if (mbd.isPrototype()) { 93 var12 = null; 94 95 Object prototypeInstance; 96 try { 97 this.beforePrototypeCreation(beanName); 98 prototypeInstance = this.createBean(beanName, mbd, args); 99 } finally { 100 this.afterPrototypeCreation(beanName); 101 } 102 103 beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 104 } else { 105 String scopeName = mbd.getScope(); 106 if (!StringUtils.hasLength(scopeName)) { 107 throw new IllegalStateException("No scope name defined for bean '" + beanName + "'"); 108 } 109 //5.类型转换 110 Scope scope = (Scope)this.scopes.get(scopeName); 111 if (scope == null) { 112 throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); 113 } 114 115 try { 116 Object scopedInstance = scope.get(beanName, () -> { 117 this.beforePrototypeCreation(beanName); 118 119 Object var4; 120 try { 121 var4 = this.createBean(beanName, mbd, args); 122 } finally { 123 this.afterPrototypeCreation(beanName); 124 } 125 126 return var4; 127 }); 128 beanInstance = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 129 } catch (IllegalStateException var30) { 130 throw new ScopeNotActiveException(beanName, scopeName, var30); 131 } 132 } 133 } catch (BeansException var32) { 134 beanCreation.tag("exception", var32.getClass().toString()); 135 beanCreation.tag("message", String.valueOf(var32.getMessage())); 136 //清除创建bean 137 this.cleanupAfterBeanCreationFailure(beanName); 138 throw var32; 139 } finally { 140 beanCreation.end(); 141 } 142 } 143 144 return this.adaptBeanInstance(name, beanInstance, requiredType); 145 }
这里面涉及到解决Spring循环依赖的问题,详情请参考文章《Spring - 如何解决循环依赖》
12. finishRefresh
主要作用:完成应用程序的上下文刷新,广播事件。其中包括:完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,发布ContextRefreshedEvent事件。
Eureka 注册会在 finishRefresh() 这个阶段。下面进行分析:
入口是在finishRefresh方法中的this.getLifecycleProcessor().onRefresh();
DefaultLifecycleProcessor#onRefresh
public void onRefresh() { // 负责启动和初始化这些已经创建的 Bean,包括执行生命周期中的初始化方法、事件监听器注册等操作。 this.startBeans(true); // 确保容器已经完全启动并处于可运行状态 this.running = true; }
Eureka 注册的时机选择在 finishRefresh() 中调用的 onRefresh() 方法,主要是因为:
1)确保容器初始化完成
Eureka 客户端是一个由 Spring 管理的 Bean,可能依赖于其他服务的配置或属性。只有在 Spring 上下文的初始化过程完成之后,所有的 Bean 才会被完全实例化和初始化。
如果在这个之前注册,可能会导致服务注册时依赖的属性尚未被注入或初始化完成,从而导致注册失败或注册时信息不全。
2)Eureka 客户端的启动依赖
在 Spring Cloud 中,Eureka 客户端通常是由 @EnableEurekaClient 或 @EnableDiscoveryClient 注解启动的,它会创建一个 EurekaClient 实例来与 Eureka 服务器通信并进行注册。EurekaClient 会在 Spring 容器启动之后连接到 Eureka 服务注册中心,并将当前应用注册到 Eureka 上。
由于 EurekaClient 是一个 Spring Bean,它的创建和注册会被推迟到 Spring 容器的初始化完成后,确保容器内的依赖和配置都已准备好。
3) 确保服务准备好注册
容器的 running 状态确保服务已经处于可用状态,服务才可以进行注册并与注册中心正常通信。
说明:无论是Dubbo 还是 Nacos,它们作为服务框架或服务注册中心,其服务注册的时机通常都在 Spring 上下文完全初始化之后,也就是在 finishRefresh() 阶段。
二、refresh()方法中比较重要的类/接口进行梳理
1. BeanFactory 接口
BeanFactory 是IoC容器的基础接口。用于管理Bean的工厂,它负责创建、解析和管理Bean对象。在容器启动时,会先创建 BeanFactory,然后根据配置信息加载并初始化 Bean。
2. BeanDefinition 接口
Spring 实例化要通过 BeanDefinition。因为 Class 是无法完成 bean 的抽象,比如 bean 的作用域,bean 的注入模型,bean 是否是懒加载等等信息,Class是无法抽象出来的,故而需要一个 BeanDefinition 类来抽象这些信息。
BeanDefinition类图如下:
3. BeanDefinitionRegistry 接口
BeanDefinitionRegistry 是 Spring 框架中的一个接口,用于注册和管理 BeanDefinition,即用于定义和描述 Spring 中的 Bean。
BeanDefinitionRegistry 接口定义了一系列方法,包括注册、移除、检索 BeanDefinition 等。通过这些方法,可以向 Spring 容器注册各种类型的 BeanDefinition,包括单例、原型、懒加载等,并指定它们的依赖关系、作用域、初始化方法、销毁方法等。
通过使用 BeanDefinitionRegistry,开发人员可以动态地向 Spring 容器注册新的 BeanDefinition,从而实现灵活的 IoC(控制反转)和 DI(依赖注入)功能
结构如下:
4. ConfigurableListableBeanFactory 接口
它继承自 ListableBeanFactory 和 ConfigurableBeanFactory 接口,主要用于配置和管理 BeanFactory。
总的来说,ConfigurableListableBeanFactory 提供了对 Spring IoC 容器的高级配置和管理功能,是 Spring 中 BeanFactory 的一个可配置的扩展接口。
5. DefaultListableBeanFactory 类
它是Spring 框架中最常用的 IOC 容器实现之一,它支持 XML 配置和基于注解的配置,并提供了丰富的功能和灵活性,因此被广泛应用于各种类型的 Spring 应用中。
它实现了 ConfigurableListableBeanFactory 和 BeanDefinitionRegistry 接口,提供了对 Bean 的定义和管理的基本功能。
DefaultListableBeanFactory 是一个基本功能的 BeanFactory,它实现了 BeanDefinitionRegistry 接口。它的继承结构如下:
DefaultListableBeanFactory 也是通过一个 HashMap 来管理 BeanDefinition 的,它比 SimpleBeanDefinitionRegistry多了一些其他的数据存储,使用上也更复杂。
下面是其中一部分代码:
//用于保存BeanDefinition /key:beanName value:BeanDefinition private final Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); //已注册的beanName,按注册的顺序有序 private volatile List<string> beanDefinitionNames = new ArrayList<>(256); //手动注册的singleton bean的名字,按注册的顺序有序 private volatile Set<string> manualsingletonNames = new LinkedHashSet<>(16);
其中 registerBeanDefinition() 方法:
负责管理 Spring IoC 容器中的 BeanDefinition,确保每个 Bean 都有一个唯一的名称,并处理覆盖和更新 BeanDefinition 的逻辑。
6. BeanFactoryPostProcessor 接口
BeanFactoryPostProcessor 负责在 BeanFactory 加载 BeanDefinition 之后,但在 Bean 实例化之前,对 BeanFactory 进行处理。这样可以在容器启动过程中对 BeanFactory 进行修改,比如注册自定义的 BeanDefinition,修改属性值,添加属性转换器等。
7. BeanPostProcessor 接口
BeanPostProcessor类:
1 public interface BeanPostProcessor { 2 3 @Nullable 4 default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 5 return bean; 6 } 7 8 @Nullable 9 default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 10 return bean; 11 } 12 13 }
1)执行时机
AbstractAutowireCapableBeanFactory#initializeBean
1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { 2 if (System.getSecurityManager() != null) { 3 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { 4 // 激活 Aware 方法 5 invokeAwareMethods(beanName, bean); 6 return null; 7 }, getAccessControlContext()); 8 } 9 else { 10 // 对特殊的 bean 处理:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware,使得 Bean 可以访问一些容器中特定的资源 11 invokeAwareMethods(beanName, bean); 12 } 13 14 Object wrappedBean = bean; 15 if (mbd == null || !mbd.isSynthetic()) { 16 //执行BeanPostProcessor所有实现类的postProcessBeforeInitialization方法 17 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 18 } 19 20 try { 21 // 激活用户自定义的 init 方法 22 invokeInitMethods(beanName, wrappedBean, mbd); 23 } 24 catch (Throwable ex) { 25 throw new BeanCreationException( 26 (mbd != null ? mbd.getResourceDescription() : null), 27 beanName, "Invocation of init method failed", ex); 28 } 29 if (mbd == null || !mbd.isSynthetic()) { 30 //执行BeanPostProcessor所有实现类的postProcessAfterInitialization方法 31 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 32 } 33 return wrappedBean; 34 }
2)注册顺序
在 Spring 中,注册后置处理器时会按照以下顺序进行排序:
- 将实现了 PriorityOrdered 接口的后置处理器添加到 priorityOrderedPostProcessors 集合中,并按照 Ordered 接口或 @Order 注解的顺序进行排序。
- 将实现了 Ordered 接口或使用 @Order 注解标注的后置处理器添加到 orderedPostProcessorNames 集合中。
- 将未实现以上接口或注解的后置处理器添加到 nonOrderedPostProcessorNames 集合中。
后置处理器的类型包括:
实现了 BeanPostProcessor 接口的后置处理器,用于在 Bean 实例化、依赖注入和初始化阶段对 Bean 进行额外的处理。
实现了 BeanFactoryPostProcessor 接口的后置处理器,用于在 BeanFactory 标准初始化后对 BeanFactory 进行额外的处理。
实现了 MergedBeanDefinitionPostProcessor 接口的后置处理器,用于在 Bean 定义合并前后对 Bean 进行额外的处理。
说明:MergedBeanDefinitionPostProcessor 接口是 BeanFactoryPostProcessor 的一个子接口,用于在 Bean 定义合并阶段进行操作,例如,可以通过这个后置处理器修改 Bean 的定义信息。
8. ApplicationContext 接口
ApplicationContext 实际上是 BeanFactory 的一个子接口,它扩展了 BeanFactory 的功能,提供了更多的企业级特性,比如国际化、事件发布、应用上下文的层级结构等。在 Spring 中,ApplicationContext 是 Spring IOC 容器的一种,而 BeanFactory 是 IOC 容器的基础接口。
ApplicationContext 不直接暴露 BeanFactory 的所有功能,而是通过代理模式对其进行封装和增强,使其具有更多的功能。这种封装和增强的方式让 ApplicationContext 具有了更强大的特性,比如自动装配、AOP(面向切面编程)、事件处理等,从而更适合于企业级应用的开发。
9. PostProcessorRegistrationDelegate 类
是 Spring 框架中用于处理后置处理器(BeanPostProcessor)的注册工具类。其主要作用是负责管理后置处理器的注册和执行顺序
参考链接:
https://cloud.tencent.com/developer/article/2302663
https://yangzhiwen911.github.io/zh/spring/