Spring源码(一)
Spring面试题
Spring
开发者通常不和AbstractApplicationContext直接打交道,
而是通过其子类如 ClassPathXmlApplicationContext(xml配置方式) 或 AnnotationConfigApplicationContext(注解配置方式)来交互
Spring启动大致流程:调用构造器链来填充前置信息->扫描xml配置信息->启动容器刷新
容器刷新流程:
- 准备前置刷新,初始化启动信息
- 获取配置工厂核心类,通常实现交由默认工厂类实现
- 工厂前置加载处理
- 完成刷新,发布刷新事件
Spring的启动
Spring的启动通常要去加载xml配置或者通过注解去扫描Bean
xml配置方式- 配置文件
example.xml<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="exampleBean" class="com.example.ExampleBean"> <property name="someProperty" value="someValue"/> </bean> </beans> - 设置
启动类public static void main(String[] args) { // 读取启动配置文件(此处的位置为类加载路径下且为非SpringBoot的原生Spring配置) ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:example.xml"); // 获取 bean 实例 MyService myService = (MyService) context.getBean("myService"); }
- 配置文件
注解方式配置- 声明Bean
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public ExampleBean exampleBean() { ExampleBean bean = new ExampleBean(); bean.setSomeProperty("someValue"); return bean; } } - 手动扫描注解配置启动类
public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); ExampleBean myBean = (ExampleBean) context.getBean("exampleBean"); }
- 声明Bean
- 其他涉及注解的方式(这些方法需要对Java的类添加指定注解,还需指定扫描的路径以及其他设置,此篇文章重点不在于此)
上述字眼皆在引入Spring源码的突破点和关联相关预备知识
作为加载配置的启动类,
不管是AnnotationConfigApplicationContext还是ClassPathXmlApplicationContext
都是继承或实现了大量的模版抽象类才具有了“启动”的功能,所以想要快速学习Spring的编码和思维方式,
模版类的学习是非常容易突破且入手的
- 以xml启动类的继承一览

虽然在基础启动类ClassPathXmlApplicationContext上继承和实现了大量类,
但对分析源码来说,所有的继承通常都是扩展,即是扩展就存在单一类可体现所有父类行为
综上,此处只对分支最多且最典型的AbstractApplicationContext进行梳理AbstractApplicationContext抽象类/* 在new ClassPathXmlApplicationContext("classpath:example.xml")中, 调用了ClassPathXmlApplicationContext类的String类型的构造参数, 而此构造参数以及重载构造参数最终都指向一个三参构造参数,关系如下 */ public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext { // 默认使用的构造参数 public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[]{configLocation}, true, (ApplicationContext)null); } // 重载参数指向的三参构造参数 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { /* 调用父级构造器,构造多层构造器链,确保每层父类被正确初始化,若不显式调用,则会在编译后默认添加super()到第一行 若是无此项采用默认的空参构造器,会缺少与父级上下文同步的设置,此设置可减少子级重新配置通用参数的工作 但是默认使用的都是String类型的构造器 其实parent为null,故此项等同于super() */ super(parent); this.setConfigLocations(configLocations); // 此项为配置文件挂载,文件不存在等健壮报错等处理 if (refresh) { /* 此处为Spring启动核心所在,详见下面的类 */ this.refresh(); } } }AbstractApplicationContext抽象模版启动核心类/* 抽象模版启动核心类 */ public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean { //... public void refresh() throws BeansException, IllegalStateException { // 锁Monitor,保证线程安全(ps:用来启停互斥,你总不能无脑开关吧?!等等,你刚刚是不是开啦?) synchronized(this.startupShutdownMonitor) { /* prepareRefresh做准备工作,日志你得加吧,时间戳,版本号,运行环境也得加吧 这可是Spring。(ps:看源码要知道学什么,自己的接口方法也要加日志, 工作的越久就会发现,这些边边角角不注意的地方,往往是开发优劣之分的关键点) */ this.prepareRefresh(); // 获取一个BeanFactory,包含启动载入的配置Bean,简言之,就是封装了一个包含Bean名称的Map(beanDefinitionMap) ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); /* 1.设置BeanFactory的类加载器。 2.设置表达式解析器(Expression Resolver),如SpEL(Spring Expression Language)解析器。 3.添加一些特殊的bean后处理器,比如用于处理@Autowired注解的自动装配基础设施。 4.注册可以解析占位符配置值的属性编辑器(PropertyEditor)。 5.注册可解决资源路径的转换服务。 */ this.prepareBeanFactory(beanFactory); try { /* 下面三行代码体现了共性的功能,都是类钩子函数 1.暴露方法给子类实现,在BeanFactory准备好,BeanFactoryPostProcessor之前调用(Bean实例化前) 2.调用所有已注册的BeanFactoryPostProcessor实例,在bean实例化之前修改bean定义。 3.这些处理器可以修改BeanFactory的配置元数据,在bean实例化之后但在初始化完成之前对bean实例进行处理。 */ this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); // 国际化i18n this.initMessageSource(); // 初始化应用事件广播器,这是一个用于发布应用事件到监听器的组件。 // 如果配置了applicationEventMulticaster bean,则使用该bean;否则,将创建一个默认的实现。(applicationEventMulticaster默认是单例) this.initApplicationEventMulticaster(); // 自定义刷新方法 this.onRefresh(); // 注册所有应用监听器(指由Spring配置注解或者xml且实现ApplicationListener接口的Bean), // 这些监听器可以接收并响应由应用上下文发布的事件 this.registerListeners(); /* 完成Bean工厂的初始化,包含工厂中所有的Bean, 确保了所有的非懒加载单例 Bean 都被实例化和初始化 SpringBean的生命周期所在 */ this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { //... } finally { this.resetCommonCaches(); } } } /* finishBeanFactoryInitialization */ protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // 看是否存在转换器Bean 有的话实例化 if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) { beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class)); } /* 处理Spring的语法解析器 eg: <bean id="myBean" class="com.example.MyBean"> <property name="message" value="${app.message}"/> </bean> 此处配置语法解析器 则会将上述的${app.message}转化为environment.getProperty("property.name") */ if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(new StringValueResolver() { public String resolveStringValue(String strVal) { return AbstractApplicationContext.this.getEnvironment().resolvePlaceholders(strVal); } }); } // LoadTimeWeaverAware 是一个未实现的接口 // 主要提供给需要在Jvm加载Class时提供对Bean的增强或者修改 String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); String[] var3 = weaverAwareNames; int var4 = weaverAwareNames.length; for(int var5 = 0; var5 < var4; ++var5) { String weaverAwareName = var3[var5]; this.getBean(weaverAwareName); } // 设置临时类加载器 beanFactory.setTempClassLoader((ClassLoader)null); // 冻结配置信息(这个时候了你还想改?) beanFactory.freezeConfiguration(); /* 预实例化所有的单例Bean 此处接口由DefaultListableBeanFactory类实现 */ beanFactory.preInstantiateSingletons(); } }ConfigurableListableBeanFactory装配工厂集大成者/* 装配工厂(集大成者),扩展了父类的功能是非常核心的接口, 拥有自动装配,管理 Bean 的定义、注册 Bean 后处理器、获取 Bean 列表等功能 */ public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory { // ... protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 设置类加载器 用来进行动态加载类,同时支持AOP等功能 beanFactory.setBeanClassLoader(this.getClassLoader()); // 设置 Bean 表达式解析器 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 注册资源编辑器 注册器 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment())); /* 向BeanFactory注册一个后处理器,这个后处理器会在每个bean实例化之后但在其初始化方法(例如@PostConstruct或InitializingBean.afterPropertiesSet())被调用之前运行。 对于实现了ApplicationContextAware接口的bean,ApplicationContextAwareProcessor会自动设置它们的ApplicationContext属性 ApplicationContextAware: 允许bean获取到应用上下文。 BeanFactoryAware: 允许bean获取到创建它的BeanFactory。 MessageSourceAware: 允许bean获取到消息源,通常用于国际化。 ResourceLoaderAware: 允许bean获取到资源加载器,这可以用来加载文件或其他类型的资源。 ApplicationEventPublisherAware: 允许bean发布事件到应用上下文中。 ServletConfigAware 和 ServletContextAware: 在Web环境中使用,分别允许bean获取到Servlet配置和Servlet上下文 ps:其实就是只要这个工厂Bean提供了这些方法的实现,那么就可以提供其需要的上下文环境和服务 */ beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 忽略依赖注入 这些接口通常由Spring自动管理 beanFactory.ignoreDependencyInterface(); // ... // 注册一些依赖供启动后直接调用,略去显示声明 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 添加监听器 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 特殊Bean处理 if (beanFactory.containsBean("loadTimeWeaver")) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 单例模式的特殊Bean if (!beanFactory.containsLocalBean("environment")) { beanFactory.registerSingleton("environment", this.getEnvironment()); } if (!beanFactory.containsLocalBean("systemProperties")) { beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean("systemEnvironment")) { beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment()); } } }DefaultListableBeanFactory跳转到特定代码public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this); } /* * 在此处this.beanDefinitionNames即为配置文件或者注解中配置的bean的名称 * 此处比较抽象,beanDefinitionNames是在refresh方法的 * ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); * 处完成的填充,此处涉及知识点比较多,obtainFreshBeanFactory的最终实现是一个抽象方法, * 需要追溯到DefaultListableBeanFactory的构造器链,且中间还穿插了许多接口模型。包括注解方法填充 */ List<String> beanNames = new ArrayList(this.beanDefinitionNames); Iterator var2 = beanNames.iterator(); // 下面是对已经获取到的bean进行判断,只针对 while(true) { while(true) { String beanName; RootBeanDefinition bd; do { do { do { if (!var2.hasNext()) { var2 = beanNames.iterator(); while(var2.hasNext()) { beanName = (String)var2.next(); /* getSingleton很有说法,此处涉及一个常见面试点:Spring单例作用域下的循环依赖(三级缓存) 概念: 正常来说Spring会依次创建类A,B,Spring创建类A, 发现类A依赖于B,此时B仍未创建,则先去创建B,Spring创建 B时发现又依赖于A,此时则出现了循环依赖 方法: 1.解决方法则是在创建B时发现依赖与A的时候,Spring创建A的过程仍未结束 那么此时则把A的ObjectFactory放入singleFactories, 并将A的实例放入earlySingletonObjects 中。 2.之后继续B的创建,此时Spring可以从earlySingletonObjects中获取 到A的实例,注入到自己的bean中完成B的初始化并且添加到singleFactories中 3.此时再次返回A的创建时,即可完成A的创建 三级缓存: singletonObjects: 存储已经完全初始化的单例 Bean 实例。 当 Bean 完全初始化后,会被放入这个缓存中。 earlySingletonObjects: 存储早期引用的单例 Bean 实例。 在 Bean 创建过程中,如果需要提前引用某个 Bean,会先将它放入这个缓存中。 singletonFactories: 存储用于生成早期引用的 ObjectFactory 对象。 如果某个 Bean 还未完全初始化,但需要提前引用,会先将它的 ObjectFactory 放入这个缓存中。 */ Object singletonInstance = this.getSingleton(beanName); // 判断当前Bean是否是SmartInitializingSingleton的实例,该实例可在所有单例Bean初始化完成后执行后置操作 if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance; // 判断当前虚拟机是否有安全管理器,如果存在,则说明当前在一个受限的环境中 // 如果存在受限环境,那么就通过doPrivileged获取当前线程所拥有的权限 if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { smartSingleton.afterSingletonsInstantiated(); return null; } }, this.getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } return; } beanName = (String)var2.next(); bd = this.getMergedLocalBeanDefinition(beanName); } while(bd.isAbstract()); } while(!bd.isSingleton()); } while(bd.isLazyInit()); if (this.isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() { public Boolean run() { return ((SmartFactoryBean)factory).isEagerInit(); } }, this.getAccessControlContext()); } else { isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit(); } if (isEagerInit) { this.getBean(beanName); } } else { this.getBean(beanName); } } } } /* getSingleton很有说法,此处涉及一个常见面试点:Spring单例作用域下的循环依赖(三级缓存) 概念: 正常来说Spring会依次创建类A,B,Spring创建类A, 发现类A依赖于B,此时B仍未创建,则先去创建B,Spring创建 B时发现又依赖于A,此时则出现了循环依赖 方法: 1.解决方法则是在创建B时发现依赖与A的时候,Spring创建A的过程仍未结束 那么此时则把A的ObjectFactory放入singleFactories, 并将A的实例放入earlySingletonObjects 中。 2.之后继续B的创建,此时Spring可以从earlySingletonObjects中获取 到A的实例,注入到自己的bean中完成B的初始化并且添加到singleFactories中 3.此时再次返回A的创建时,即可完成A的创建 三级缓存: singletonObjects: 存储已经完全初始化的单例 Bean 实例。 当 Bean 完全初始化后,会被放入这个缓存中。 earlySingletonObjects: 存储早期引用的单例 Bean 实例。 在 Bean 创建过程中,如果需要提前引用某个 Bean,会先将它放入这个缓存中。 singletonFactories: 存储用于生成早期引用的 ObjectFactory 对象。 如果某个 Bean 还未完全初始化,但需要提前引用,会先将它的 ObjectFactory 放入这个缓存中。 */ protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) { synchronized(this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } } }