Spring应用上下文 ApplicationContext
xsobi 2024-11-24 23:33 1 浏览
Spring 应用上下文 ApplicationContext
前面一系列文章都是围绕 BeanFactory 进行分析的,BeanFactory 是 Spring 底层 IoC 容器的实现,完成了 IoC 容器的基本功能。在实际的应用场景中,BeanFactory 容器有点简单,它并不适用于生产环境,我们通常会选择 ApplicationContext。ApplicationContext 就是大名鼎鼎的 Spring 应用上下文,它不仅继承了 BeanFactory 体系,还提供更加高级的功能,更加适用于我们的正式应用环境。如以下几个功能:
- 继承 MessageSource,提供国际化的标准访问策略
- 继承 ApplicationEventPublisher ,提供强大的事件机制
- 扩展 ResourceLoader,可以用来加载多个 Resource,可以灵活访问不同的资源
- 对 Web 应用的支持
ApplicationContext 体系结构
先来看看 ApplicationContext 接口的继承关系
可以看到 ApplicationContext 除了继承 BeanFactory 接口以外,还继承了 MessageSource、ApplicationEventPublisher、ResourceLoader 等接口
简单描述几个接口:
- org.springframework.core.io.ResourceLoader,资源加载接口,用于访问不同的资源
- org.springframework.context.ApplicationEventPublisher,事件发布器接口,支持发布事件
- org.springframework.context.MessageSource,消息资源接口,提供国际化的标准访问策略
- org.springframework.core.env.EnvironmentCapable,环境暴露接口,Spring 应用上下文支持多环境的配置
- org.springframework.context.ApplicationContext,Spring 应用上下文,仅可读
- org.springframework.context.ConfigurableApplicationContext,Spring 应用上下文,支持配置相关属性
接下来我们来看看它们的实现类的继承关系(部分)
简单描述上面几个关键的类:
- org.springframework.context.support.AbstractApplicationContext,Spring 应用上下文的抽象类,实现了大部分功能,提供骨架方法交由子类去实现
- org.springframework.web.context.ConfigurableWebApplicationContext,可配置的 Spring 应用上下文接口,支持 Web 应用
- org.springframework.context.support.AbstractRefreshableConfigApplicationContext,支持设置 XML 文件
- org.springframework.web.context.support.AbstractRefreshableWebApplicationContext,支持 Web 应用
- org.springframework.web.context.support.AnnotationConfigWebApplicationContext,支持 Web 应用,可以设置 XML 文件,并可以扫描注解下面的 Bean
- org.springframework.context.annotation.AnnotationConfigApplicationContext,支持扫描注解下面的 Bean
- org.springframework.web.context.support.ClassPathXmlApplicationContext,支持设置 XML 文件,也可以从 classpath 下面扫描相关资源
ApplicationContext 的子类比较多,主要根据支持 Web、支持注解、支持 XML 文件三个功能进行区分,我们大致了解每个实现类的作用即可。其中基本的实现都是在 AbstractApplicationContext 这个抽象类中完成的,在它的 refresh() 方法体现了 Spring 应用上下文的生命周期。AbstractApplicationContext#refresh() 这个方法可以说是 Spring 应用上下文的准备阶段,在使用 Spring 时该方法会被调用,本文就围绕它进行展述。
可以先看到我的另一篇文章《精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化》,在 Spring MVC 启动过程中,创建 Spring 应用上下文后会调用其 refresh() 方法进行刷新,让 Spring 应用上下文准备就绪。
AbstractApplicationContext
org.springframework.context.support.AbstractApplicationContext,Spring 应用上下文的抽象类,实现了大部分功能,提供骨架方法交由子类去实现
先来看看它的相关属性
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
static {
// Eagerly load the ContextClosedEvent class to avoid weird classloader issues
// on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
ContextClosedEvent.class.getName();
}
/** Unique id for this context, if any. */
private String id = ObjectUtils.identityToString(this);
/** Display name. */
private String displayName = ObjectUtils.identityToString(this);
/** 父应用上下文 */
@Nullable
private ApplicationContext parent;
/** 当前应用上下文的环境 */
@Nullable
private ConfigurableEnvironment environment;
/** BeanFactory 的处理器 */
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
/** 启动时间 */
private long startupDate;
/** 是否处于激活状态 */
private final AtomicBoolean active = new AtomicBoolean();
/** 是否处于关闭状态 */
private final AtomicBoolean closed = new AtomicBoolean();
/** 启动和销毁时的锁对象 */
private final Object startupShutdownMonitor = new Object();
/** 钩子函数,用于 JVM 关闭时的回调 */
@Nullable
private Thread shutdownHook;
/** ResourcePatternResolver used by this context. */
private ResourcePatternResolver resourcePatternResolver;
/** LifecycleProcessor for managing the lifecycle of beans within this context. */
@Nullable
private LifecycleProcessor lifecycleProcessor;
/** MessageSource we delegate our implementation of this interface to. */
@Nullable
private MessageSource messageSource;
/** 事件广播器 */
@Nullable
private ApplicationEventMulticaster applicationEventMulticaster;
/** 事件监听器 */
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
/** 早期(Spring 应用上下文还未就绪)注册的时间监听器 */
@Nullable
private Set<ApplicationListener<?>> earlyApplicationListeners;
/** 早期(Spring 应用上下文还未就绪)发布的事件 */
@Nullable
private Set<ApplicationEvent> earlyApplicationEvents;
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
}
}
属性不多,上面都有注释
publishEvent 方法
publishEvent(ApplicationEvent event) 方法,发布事件,因为它继承了 ApplicationEventPublisher 事件发布器,如下:
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
// 如果不是 ApplicationEvent 类型的事件,则封装成 PayloadApplicationEvent
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 广播该事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
// 父容器也要发布事件
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
过程如下:
- 如果不是 ApplicationEvent 类型的事件,则封装成 PayloadApplicationEvent
- 如果 earlyApplicationEvents 不为 null,则表示当前 Spring 应用上下文正在处于刷新阶段,还没有准备就绪,则先将这个早期事件添加至 earlyApplicationEvents;否则,Spring 应用上下文已经准备就绪了,此时就对该事件进行广播
- 如果存在父应用上下文,也需要进行广播
上面的第 2 步中的 earlyApplicationEvents 如果不为 null ,为什么 Spring 应用上下文还没有准备就绪呢?答案会在后面体现
addBeanFactoryPostProcessor 方法
addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) 方法,添加 BeanFactoryPostProcessor 处理器,如下:
@Override
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
直接往 beanFactoryPostProcessors 添加,BeanFactoryPostProcessor 处理器用于在 Spring 应用上下文刷新阶段对创建好的 BeanFactory 进行后缀处理
addApplicationListener 方法
addApplicationListener(ApplicationListener<?> listener) 方法,添加事件监听器,如下:
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
Assert.notNull(listener, "ApplicationListener must not be null");
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
this.applicationListeners.add(listener);
}
如果事件广播器不为空则将该监听器添加进去,然后再添加到本地的 applicationListeners 中
【核心】refresh 方法
refresh() 方法,Spring 应用上下文的刷新,让 Spring 应用上下文处于准备就绪状态,如下:
/**
* 刷新上下文,在哪会被调用?
* 在 **Spring MVC** 中,{@link org.springframework.web.context.ContextLoader#initWebApplicationContext} 方法初始化上下文时,会调用该方法
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
// <1> 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized (this.startupShutdownMonitor) {
// <2> 刷新上下文环境的准备工作,记录下容器的启动时间、标记'已启动'状态、对上下文环境属性进行校验
prepareRefresh();
// <3> 创建并初始化一个 BeanFactory 对象 `beanFactory`,会加载出对应的 BeanDefinition 元信息们
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// <4> 为 `beanFactory` 进行一些准备工作,例如添加几个 BeanPostProcessor,手动注册几个特殊的 Bean
prepareBeanFactory(beanFactory);
try {
// <5> 对 `beanFactory` 在进行一些后期的加工,交由子类进行扩展
postProcessBeanFactory(beanFactory);
// <6> 执行 BeanFactoryPostProcessor 处理器,包含 BeanDefinitionRegistryPostProcessor 处理器
invokeBeanFactoryPostProcessors(beanFactory);
// <7> 对 BeanPostProcessor 处理器进行初始化,并添加至 BeanFactory 中
registerBeanPostProcessors(beanFactory);
// <8> 设置上下文的 MessageSource 对象
initMessageSource();
// <9> 设置上下文的 ApplicationEventMulticaster 对象,上下文事件广播器
initApplicationEventMulticaster();
// <10> 刷新上下文时再进行一些初始化工作,交由子类进行扩展
onRefresh();
// <11> 将所有 ApplicationListener 监听器添加至 `applicationEventMulticaster` 事件广播器,如果已有事件则进行广播
registerListeners();
// <12> 设置 ConversionService 类型转换器,**初始化**所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式)
finishBeanFactoryInitialization(beanFactory);
// <13> 刷新上下文的最后一步工作,会发布 ContextRefreshedEvent 上下文完成刷新事件
finishRefresh();
}
// <14> 如果上面过程出现 BeansException 异常
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// <14.1> “销毁” 已注册的单例 Bean
destroyBeans();
// <14.2> 设置上下文的 `active` 状态为 `false`
cancelRefresh(ex);
// <14.3> 抛出异常
throw ex;
}
// <15> `finally` 代码块
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
// 清除相关缓存,例如通过反射机制缓存的 Method 和 Field 对象,缓存的注解元数据,缓存的泛型类型对象,缓存的类加载器
resetCommonCaches();
}
}
}
整个过程比较长,每一个步骤都调用一个方法,过程如下:
- 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
- 应用上下文启动准备阶段,调用 prepareRefresh() 方法,说明:刷新上下文环境的准备工作,记录下容器的启动时间、标记'已启动'状态、对上下文环境属性进行校验
- BeanFactory 创建阶段,调用 obtainFreshBeanFactory() 方法,说明:创建并初始化一个 BeanFactory 对象 beanFactory,会加载出对应的 BeanDefinition 元信息们
- BeanFactory 准备阶段,调用 prepareBeanFactory() 方法,说明:为 beanFactory 进行一些准备工作,例如添加几个 BeanPostProcessor,手动注册几个特殊的 Bean
- BeanFactory 后置处理阶段,调用 postProcessBeanFactory(ConfigurableListableBeanFactory) 方法,说明:对 beanFactory 在进行一些后期的加工,交由子类进行扩展
- BeanFactory 后置处理阶段,调用 invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) 方法,说明:执行 BeanFactoryPostProcessor 处理器,包含 BeanDefinitionRegistryPostProcessor 处理器
- BeanFactory 注册 BeanPostProcessor 阶段,调用 registerBeanPostProcessors(ConfigurableListableBeanFactory) 方法,说明:对 BeanPostProcessor 处理器进行初始化,并添加至 BeanFactory 中
- 初始化内建 Bean:MessageSource,调用 initMessageSource() 方法,说明:设置上下文的 MessageSource 对象
- 初始化内建 Bean:Spring 事件广播器,调用 initApplicationEventMulticaster() 方法,说明:设置上下文的 ApplicationEventMulticaster 对象,上下文事件广播器
- Spring 应用上下文刷新扩展阶段,调用 onRefresh() 方法,说明:刷新上下文时再进行一些初始化工作,交由子类进行扩展
- Spring 事件监听器注册阶段,调用 registerListeners() 方法,说明:将所有 ApplicationListener 监听器添加至 applicationEventMulticaster 事件广播器,如果已有事件则进行广播
- BeanFactory 初始化完成阶段,调用 finishBeanFactoryInitialization(ConfigurableListableBeanFactory) 方法,说明:设置 ConversionService 类型转换器,初始化所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式)
- 应用上下文刷新完成阶段,调用 finishRefresh() 方法,说明:刷新上下文的最后一步工作,会发布 ContextRefreshedEvent 上下文完成刷新事件
- 如果上面过程出现 BeansException 异常“销毁” 已注册的单例 Bean设置上下文的 active 状态为 false抛出异常
- finally 代码块,清除相关缓存,例如通过反射机制缓存的 Method 和 Field 对象,缓存的注解元数据,缓存的泛型类型对象,缓存的类加载器
可以看到该过程分为许多阶段,每个阶段都非常关键,将在后续已经进行分析
registerShutdownHook 方法
registerShutdownHook() 方法,向 JVM 注册一个钩子函数,当 JVM 关闭时执行该函数,如下:
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread() {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
// 为当前的 JVM 运行环境添加一个钩子函数,用于关闭当前上下文
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
这个钩子函数也就是调用了 doClose() 方法,用于关闭当前 Spring 应用上下文
close 方法
close() 方法,关闭当前 Spring 应用上下文,如下:
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}
关闭当前 Spring 应用上下文,也是调用 doClose() 方法,同时如果存在钩子函数则将其从 JVM 中移除,因为上面已经关闭了
doClose 方法
doClose() 方法,关闭当前 Spring 应用上下文,如下:
protected void doClose() {
// Check whether an actual close attempt is necessary...
if (this.active.get() && this.closed.compareAndSet(false, true)) {
// Live Beans JMX 撤销托管
LiveBeansView.unregisterApplicationContext(this);
try {
// Publish shutdown event.
// 发布当前 Spring 应用上下文关闭事件
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
if (this.lifecycleProcessor != null) {
try {
// 关闭 Lifecycle Beans
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}
// Destroy all cached singletons in the context's BeanFactory.
// 销毁所有的单例 Bean
destroyBeans();
// Close the state of this context itself.
// 关闭底层 BeanFactory 容器
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
// 提供给子类去实现,用于清理相关资源
onClose();
// Reset local application listeners to pre-refresh state.
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Switch to inactive.
this.active.set(false);
}
}
主要做以下事情:
- Live Beans JMX 撤销托管
- 发布当前 Spring 应用上下文关闭事件
- 销毁所有的单例 Bean,调用 DefaultListableBeanFactory#destroySingletons() 方法
- 关闭底层 BeanFactory 容器
- 回调 onClose() 方法
1. 应用上下文启动准备阶段
AbstractApplicationContext#prepareRefresh() 方法,如下:
// AbstractApplicationContext.java
protected void prepareRefresh() {
// 设置启动时间
this.startupDate = System.currentTimeMillis();
// 设置当前 ApplicationContext 的状态
this.closed.set(false);
this.active.set(true);
// Initialize any placeholder property sources in the context environment.
// 初始化 ApplicationContext 的 Environment(上下文环境)的相关属性,交由子类去实现,如果是 Web 则会设置 ServletContext 和 ServletConfig
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 对属性进行必要的验证
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
主要做了以下事情:
- 设置启动时间:startupDate
- 设置 Spring 应用上下文的状态标识:closed(false)、active(true)
- 初始化 PropertySources - initPropertySources(),初始化 ApplicationContext 的 Environment(上下文环境)的相关属性,交由子类去实现,如果是 Web 则会设置 ServletContext 和 ServletConfig
- 校验 Environment 中必须属性
- 初始化早期 Spring 事件集合 earlyApplicationEvents,注意这里创建了一个空的集合,也就是不为 null,回到前面的 publishEvent(...) 方法,如果 earlyApplicationEvents 不为 null 则会添加到这个集合里面,不会进行广播。这一步的目的就是在 Spring 应用上下文还未完全就绪时,如果发布了事件,则需要先存储起来,等就绪后才进行广播
2. BeanFactory 创建阶段
整个过程会创建一个 DefaultListableBeanFactory 对象作为底层 IoC 容器,然后从资源文件或者根据指定路径下 .class 文件(标注了@ Component 注解)加载出所有的 BeanDefinition
2.1 obtainFreshBeanFactory 方法
AbstractApplicationContext#obtainFreshBeanFactory() 方法,如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
这两个方法都是抽象方法,交由子类实现,我们来看到 AbstractRefreshableApplicationContext 的实现
2.2 refreshBeanFactory 方法
AbstractRefreshableApplicationContext#refreshBeanFactory() 方法,如下:
@Override
protected final void refreshBeanFactory() throws BeansException {
// 若已有 BeanFactory ,销毁它的 Bean 们,并销毁 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建 DefaultListableBeanFactory 对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 指定序列化编号
beanFactory.setSerializationId(getId());
// 定制 BeanFactory 相关属性(是否允许 BeanDefinition 重复定义,是否允许循环依赖,默认都是允许)
customizeBeanFactory(beanFactory);
// 加载 BeanDefinition 们
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
主要做以下事情:
- 若已有 BeanFactory ,销毁它的 Bean 们,并销毁 BeanFactory
- 创建 BeanFactory,DefaultListableBeanFactory 对象
- 设置 BeanFactory Id
- 定制 BeanFactory 相关属性(是否允许 BeanDefinition 重复定义,是否允许循环依赖,默认都是允许)
- 加载出 BeanDefinition 们 - loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法,交由子类实现(主要是 XML 和 Annotation 的区别)
- 关联 BeanFactory 到 Spring 应用上下文(ApplicationContext)
上面第 6 步会将第 2 步创建的 DefaultListableBeanFactory 设置为 Spring 应用上下文的 BeanFactory 对象,也就可以通过 getBeanFactory() 获取
我们再来看到 loadBeanDefinitions(...) 抽象方法的实现,主要为注解和 XML 的区别,先来看到 AbstractXmlApplicationContext 的实现
2.3 loadBeanDefinitions 方法(XML)
AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法,如下:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 创建 XmlBeanDefinitionReader 对象
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
// 对 XmlBeanDefinitionReader 进行环境变量的设置
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
// 对 XmlBeanDefinitionReader 进行设置,可以进行覆盖
initBeanDefinitionReader(beanDefinitionReader);
// 从 Resource 们中,加载 BeanDefinition 们
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 从配置文件 Resource 中,加载 BeanDefinition 们
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 从配置文件地址中,加载 BeanDefinition 们
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
可以看到这里创建了 《BeanDefinition 的加载阶段(XML 文件)》这篇文章中讲到的 XmlBeanDefinitionReader 资源解析器对象,然后通过它解析 XML 配置文件,解析过程在之前的文章中已经分析过了。
配置文件怎么来的呢?
在 《精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化》的 ContextLoader#configureAndRefreshWebApplicationContext(...) 方法中可以看到,会将 web.xml 文件中配置的 contextConfigLocation 设置到 Spring 应用上下文中
我们再来看到 AnnotationConfigWebApplicationContext 的实现
2.3 loadBeanDefinitions 方法(注解)
AnnotationConfigWebApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 方法,如下:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.componentClasses.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Registering component classes: [" +
StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
}
reader.register(ClassUtils.toClassArray(this.componentClasses));
}
if (!this.basePackages.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
// 扫描指定包路径下 @Component 注解的 .class 文件,会解析出 BeanDefinition 对象
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
if (logger.isTraceEnabled()) {
logger.trace("Registering [" + configLocation + "]");
}
reader.register(clazz);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class for config location [" + configLocation +
"] - trying package scan. " + ex);
}
int count = scanner.scan(configLocation);
if (count == 0 && logger.isDebugEnabled()) {
logger.debug("No component classes found for specified class/package [" + configLocation + "]");
}
}
}
}
}
protected ClassPathBeanDefinitionScanner getClassPathBeanDefinitionScanner(DefaultListableBeanFactory beanFactory) {
return new ClassPathBeanDefinitionScanner(beanFactory, true, getEnvironment());
}
我们主要看到关键的一步,会创建一个 ClassPathBeanDefinitionScanner 扫描器对象,然后调用其 scan(String... basePackages) 方法去扫描指定包路径下的 .class 文件,整个扫描过程在 《BeanDefinition 的解析过程(面向注解)》 这篇文章中已经分析过了
3. BeanFactory 准备阶段
AbstractApplicationContext#prepareBeanFactory(ConfigurableListableBeanFactory) 方法,如下:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置 ClassLoader 类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置 BeanExpressionResolver 表达式语言处理器,Spring 3 开始增加了对语言表达式的支持,例如可以使用 #{bean.xxx} 的形式来调用这个 Bean 的属性值
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 添加一个默认的 PropertyEditorRegistrar 属性编辑器
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
/*
* 添加一个 BeanPostProcessor 处理器,ApplicationContextAwareProcessor,初始化 Bean 的**前置**处理
* 这个 BeanPostProcessor 其实是对几种 Aware 接口的处理,调用其 setXxx 方法
* 可以跳到 AbstractAutowireCapableBeanFactory 的 initializeBean(...) 方法(调用 Bean 的初始化方法)中看看
*/
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 忽略 Aware 回调接口作为依赖注入接口
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 设置几个自动装配的特殊规则,当你自动注入下面这些类型的 Bean 时,注入的就是右边的值
// 可以看到 ApplicationContext.class 对应当前对象
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
// 添加一个 BeanPostProcessor 处理器,ApplicationListenerDetector,用于装饰监听器
// 初始化 Bean 的时候,如果是 ApplicationListener 类型且为单例模式,则添加到 Spring 应用上下文
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 增加对 AspectJ 的支持,AOP 相关
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册几个 ApplicationContext 上下文默认的 Bean 对象
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
主要做以下事情:
- 设置 ClassLoader 类加载器
- 设置 BeanExpressionResolver 表达式语言处理器,Spring 3 开始增加了对语言表达式的支持,例如可以使用 #{bean.xxx} 的形式来获取这个 Bean 的属性值
- 添加一个默认的 PropertyEditorRegistrar 属性编辑器 - ResourceEditorRegistrar
- 添加一个 BeanPostProcessor 处理器 - ApplicationContextAwareProcessor,相关 Aware 回调接口的实现,调用其 setXxx 方法
- 忽略 Aware 回调接口作为依赖注入接口
- 注册 ResolvableDependency 对象 - BeanFactory、ResourceLoader、ApplicationEventPublisher 以及 ApplicationContext,依赖注入这几个对象时注入的都是当前 Spring 应用上下文,在《@Autowired 等注解的实现原理》这篇文章中有讲到
- 添加一个 BeanPostProcessor 处理器 - ApplicationListenerDetector,初始化 Bean 的时候,如果是 ApplicationListener 类型且为单例模式,则添加到 Spring 应用上下文
- 添加一个 BeanPostProcessor 处理器 - LoadTimeWeaverAwareProcessor,增加对 AspectJ 的支持,AOP 相关
- 注册几个单例对象 - Environment、SystemProperties(Java System Properties)、SystemEnvironment(OS 环境变量)
4. BeanFactory 后置处理阶段
有序地执行所有 BeanFactoryPostProcessor(包括 BeanDefinitionRegistryPostProcessor)处理器,例如 @Bean 等注解定义的 Bean 的就是通过 BeanDefinitionRegistryPostProcessor 处理器接续出来的
4.1 postProcessBeanFactory 方法
该抽象方法交由子类实现,例如 AbstractRefreshableWebApplicationContext#postProcessBeanFactory(ConfigurableListableBeanFactory) 方法,如下:
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 添加 ServletContextAwareProcessor 到 BeanFactory 容器中,
// 该 processor 实现 BeanPostProcessor 接口,主要用于将 ServletContext 传递给实现了 ServletContextAware 接口的 bean
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
// 忽略 ServletContextAware、ServletConfigAware,上面的 ServletContextAwareProcessor 已代替
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
// 注册 WEB 应用特定的域(scope)到 beanFactory 中,以便 WebApplicationContext 可以使用它们。
// 比如'request','session','globalSession','application'
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
// 注册 WEB 应用特定的 Environment bean 到 beanFactory 中,以便 WebApplicationContext 可以使用它们
// 如:'contextParameters','contextAttributes'
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
添加 ServletContext 相关内容
4.2 invokeBeanFactoryPostProcessors 方法
AbstractApplicationContext#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) 方法,如下:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 执行所有的BeanFactoryPostProcessor处理器
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
// 在 prepareBeanFactory() 方法中也有相同操作
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
这里借助于 PostProcessorRegistrationDelegate 这个类执行所有 BeanFactoryPostProcessor 处理器,对前面创建的 BeanFactory 进行后置处理
4.3 invokeBeanFactoryPostProcessors 方法
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法,如下(方法比较长,可直接查看下面的总结):
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
// <1> 执行当前 Spring 应用上下文和底层 BeanFactory 容器中的 BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor 们的处理
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// <1.1> 先遍历当前 Spring 应用上下文中的 `beanFactoryPostProcessors`,如果是 BeanDefinitionRegistryPostProcessor 类型则进行处理
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor;
// 执行
registryProcessor.postProcessBeanDefinitionRegistry(registry);
// 添加,以供后续执行其他 `postProcessBeanFactory(registry)` 方法
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
// 临时变量,用于临时保存 BeanFactory 容器中的 BeanDefinitionRegistryPostProcessor 对象
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// <1.2> 获取底层 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor 类型的 Bean 们,遍历进行处理
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 如果实现了 PriorityOrdered 接口,则获取到对应的 Bean
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 初始化
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 临时保存起来
registryProcessors.addAll(currentRegistryProcessors);
// 执行
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 清理
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// <1.3> 获取底层 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor 类型的 Bean 们,遍历进行处理
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 如果实现了 Ordered 接口并且没有执行过,则获取到对应的 Bean
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { // Ordered类型
// 初始化
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 临时保存起来
registryProcessors.addAll(currentRegistryProcessors);
// 执行
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 清理
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
// <1.4> 获取底层 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor 类型的 Bean 们,遍历进行处理
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 如果该 BeanDefinitionRegistryPostProcessors 在上述过程中没有执行过,则获取到对应的 Bean
if (!processedBeans.contains(ppName)) {
// 初始化
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 临时保存起来
registryProcessors.addAll(currentRegistryProcessors);
// 执行
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 清理
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
/*
* <1.5> 上述执行完当前 Spring 应用上下文和底层 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor 处理器中的 postProcessBeanDefinitionRegistry(registry) 方法后,
* 接下来执行它们的 postProcessBeanFactory(beanFactory) 方法
*
* 注意:BeanDefinitionRegistryPostProcessor 继承 BeanFactoryPostProcessor 接口
*/
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
/*
* <1.6> 这里我们执行当前 Spring 应用上下文中 BeanFactoryPostProcessor 处理器(非 BeanDefinitionRegistryPostProcessors 类型)的
* postProcessBeanFactory(beanFactory) 方法
*
* 例如:PropertyPlaceholderConfigurer、PropertySourcesPlaceholderConfigurer
*/
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
// <2> 执行当前 Spring 应用上下文中的 BeanFactoryPostProcessor 处理器的 postProcessBeanFactory(beanFactory) 方法
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// <3> 获取底层 BeanFactory 容器中所有 BeanFactoryPostProcessor 类型的 Bean 们
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) { // 上面已经执行过了则跳过
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // PriorityOrdered
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { // Ordered
orderedPostProcessorNames.add(ppName);
}
else { // nonOrder
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
// <3.1> PriorityOrdered 类型的 BeanFactoryPostProcessor 对象
// 排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 执行
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
// <3.2> Ordered 类型的 BeanFactoryPostProcessor 对象
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
// 排序
sortPostProcessors(orderedPostProcessors, beanFactory);
// 执行
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
// <3.2> nonOrdered 的 BeanFactoryPostProcessor 对象
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
// 无需排序,直接执行
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
主要做以下事情:
- 如果当前 Spring 应用上下文是 BeanDefinitionRegistry 类型,则执行当前 Spring 应用上下文中所有 BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor 的处理,以及底层 BeanFactory 容器中 BeanDefinitionRegistryPostProcessor 的处理,处理顺序如下:当前 Spring 应用上下文中所有 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry底层 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(优先级:PriorityOrdered > Ordered > 无)当前 Spring 应用上下文和底层 BeanFactory 容器中所有 BeanDefinitionRegistryPostProcessor#postProcessBeanFactory当前 Spring 应用上下文中所有 BeanFactoryPostProcessor#postProcessBeanFactory
- 否则,执行当前 Spring 应用上下文中所有 BeanFactoryPostProcessor#postProcessBeanFactory
- 执行底层 BeanFactory 容器中所有 BeanFactoryPostProcessor#postProcessBeanFactory,上面已经处理过的会跳过,执行顺序和上面一样:PriorityOrdered > Ordered > 无
总结:有序地执行所有 BeanFactoryPostProcessor(包括 BeanDefinitionRegistryPostProcessor)处理器
5. BeanFactory 注册 BeanPostProcessor 阶段
将所有已加载出来的 BeanPostProcessor 类型的 BeanDefinition 通过依赖查找获取到 Bean 们,然后有序的添加至 BeanFactory 中
AbstractApplicationContext#registerBeanPostProcessors(ConfigurableListableBeanFactory) 方法,如下:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
这里也借助于 PostProcessorRegistrationDelegate 这个类注册所有 BeanPostProcessor 处理器,如下:
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// <1> 获取所有的 BeanPostProcessor 类型的 beanName
// 这些 beanName 都已经全部加载到容器中去,但是没有实例化
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
// <2> 记录所有的 BeanPostProcessor 数量,为什么加 1 ?因为下面又添加了一个
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
// 注册 BeanPostProcessorChecker,它主要是用于在 BeanPostProcessor 实例化期间记录日志
// 当 Spring 中高配置的后置处理器还没有注册就已经开始了 bean 的实例化过程,这个时候便会打印 BeanPostProcessorChecker 中的内容
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered, Ordered, and the rest.
// <3> 开始注册 BeanPostProcessor
// 实现了 `PriorityOrdered` 接口的 BeanPostProcessor 对应的 Bean 集合
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// MergedBeanDefinitionPostProcessor 类型对应的 Bean 集合
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
// 实现了 `Ordered` 接口的 BeanPostProcessor 对应的 beanName 集合
List<String> orderedPostProcessorNames = new ArrayList<>();
// 没有顺序的 BeanPostProcessor 对应的 beanName 集合
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
// PriorityOrdered
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 调用 getBean(...) 方法获取该 BeanPostProcessor 处理器的 Bean 对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
// Ordered
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
// 无序
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
// 第一步,对所有实现了 PriorityOrdered 的 BeanPostProcessor 进行排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 进行注册,也就是添加至 DefaultListableBeanFactory 中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
// 第二步,获取所有实现了 Ordered 接口的 BeanPostProcessor 对应的 Bean 们
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
// 调用 getBean(...) 方法获取该 BeanPostProcessor 处理器的 Bean 对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
// 对所有实现了 Ordered 的 BeanPostProcessor 进行排序
sortPostProcessors(orderedPostProcessors, beanFactory);
// 进行注册,也就是添加至 DefaultListableBeanFactory 中
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
// 第三步注册所有无序的 BeanPostProcessor
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String ppName : nonOrderedPostProcessorNames) {
// 调用 getBean(...) 方法获取该 BeanPostProcessor 处理器的 Bean 对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
// 注册,无需排序
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
// 最后,注册所有的 MergedBeanDefinitionPostProcessor 类型的 Bean 们
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
// 重新注册 ApplicationListenerDetector(探测器),用于探测内部 ApplicationListener 类型的 Bean
// 在完全初始化 Bean 后,如果是 ApplicationListener 类型且为单例模式,则添加到 Spring 应用上下文
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
主要做以下事情:
- 获取所有 BeanPostProcessor 类型的 beanName
- 添加 BeanPostProcessor - BeanPostProcessorChecker,用于打印日志(所有 BeanPostProcessor 还没有全部实例化就有 Bean 初始化完成)
- 获取所有 BeanPostProcessor 实现类(依赖查找),添加至 BeanFactory 容器中(顺序:PriorityOrdered > Ordered > 无)
- 注意,第 3 步添加的 BeanPostProcessor 如果是 MergedBeanDefinitionPostProcessor 类型,会再次添加(先移除再添加,也就是将顺序往后挪)
- 重新添加 BeanPostProcessor - ApplicationListenerDetector,目的将其移至最后,因为这个后置处理器用于探测 ApplicationListener 类型的 Bean,需要保证 Bean 完全初始化,放置最后比较合适
对与上述第 4 步是否疑惑?我的理解是 MergedBeanDefinitionPostProcessor 主要是依赖注入的实现,需要保证当前 Spring Bean 的相关初始化工作已完成,然后再进行依赖注入
总结:将所有已加载出来的 BeanPostProcessor 类型的 BeanDefinition 通过依赖查找获取到 Bean 们,然后有序的添加至 BeanFactory 中
6. 初始化内建 Bean:MessageSource
AbstractApplicationContext#initMessageSource() 方法,如下:
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果当前上下文中包含名称为 `messageSource` 的 Bean 对象
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// 如果有父 ApplicationContext,并且 `messageSource` 为 HierarchicalMessageSource 对象,分级处理的 MessageSource
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource registered already.
// 如果 `messageSource` 没有注册父 MessageSource,则设置为父类上下文的的 MessageSource
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
else {
// Use empty MessageSource to be able to accept getMessage calls.
// 使用空 MessageSource
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}
初始化当前 Spring 应用上下文的 MessageSource 对象,MessageSource 对象和国际化文案相关,Spring 默认情况不提供国际化文案,但是 MessageSource Bean 对象(空实现)是存在的,在 Spring Boot 中有实现,参考 MessageSourceAutoConfiguration 自动装配类
7. 初始化内建 Bean:Spring 事件广播器
AbstractApplicationContext#initApplicationEventMulticaster() 方法,如下:
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 如果当前上下文中包含名称为 `applicationEventMulticaster` 的 Bean 对象
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
else {
// 没有则新建 SimpleApplicationEventMulticaster,并将该 Bean 注册至当前上下文
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
初始化当前 Spring 应用上下文的 ApplicationEventMulticaster 事件广播器对象,Spring 默认情况下为 SimpleApplicationEventMulticaster 对象
8.应用上下文刷新扩展阶段
AbstractApplicationContext#onRefresh() 方法,空方法,交由子类实现,如 AbstractRefreshableWebApplicationContext 的实现
@Override
protected void onRefresh() {
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}
Web 场景下的 Spring 应用上下文会初始化 ThemeSource 对象
9. Spring 事件监听器注册阶段
AbstractApplicationContext#registerListeners() 方法,如下:
protected void registerListeners() {
// <1> 将当前 Spring 应用上下文已有的事件监听器依次添加至事件广播器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// <2> 从底层 BeanFactory 容器中获取所有 ApplicationListener 类型的 beanName 们(还未初始化),然后依次添加至事件广播器
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
//<3> 至此,已经完成将事件监听器全部添加至事件广播器,接下来将早期的事件通过该事件广播器广播到所有的事件监听器
// 早期事件:在当前 Spring 应用上下文刷新的过程中已经发布的事件(此时发布不会被监听到,因为事件监听器才刚全部找到,需要到此处通过事件广播器进行广播)
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
/**
* 将 `earlyApplicationEvents` 置为 `null`
* 这里很关键!!!后续发布的事件不再是早期事件,会立即被事件广播器广播。因为当前 Spring 应用中的事件广播器已经就绪了,事件监听器也都获取到了(虽然还没有初始化)
* 不过在下面广播的时候,如果事件监听器能够处理该事件,则会通过依赖注入的方式初始化该事件监听器
*/
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
// 广播该事件,能够处理该事件的事件监听器会被初始化
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
主要做以下事情:
- 将当前 Spring 应用上下文已有的事件监听器依次添加至事件广播器
- 从底层 BeanFactory 容器中获取所有 ApplicationListener 类型的 beanName 们(还未初始化),然后依次添加至事件广播器
- 复制全部的 earlyApplicationEvents 早期事件,然后将 earlyApplicationEvents 置为 null
- 广播早期事件,如果事件监听器能够处理该事件,则会通过依赖注入的方式初始化该事件监听器
早期事件:在当前 Spring 应用上下文刷新的过程中已经发布的事件(此时发布不会被监听到,因为事件监听器才刚全部找到,需要到此处通过事件广播器进行广播)
上面第 3 步会将 earlyApplicationEvents 置为 null,前面的 publishEvent 方法中你可以看到,如果该对象为 null 则会直接广播事件
10. BeanFactory 初始化完成阶段
主要为底层 BeanFactory 容器设置 ConversionService 类型转换器,初始化所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式)
finishBeanFactoryInitialization 方法
AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory) 方法,如下:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 如果底层 BeanFactory 容器包含 ConversionService 类型转换器,则初始化并设置到底层 BeanFactory 容器的属性中
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 如果底层 BeanFactory 容器没有设置 StringValueResolver 解析器,则添加一个 PropertySourcesPropertyResolver 解析器
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
// 提前初始化 LoadTimeWeaverAware 类型的 Bean,AOP 相关
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
// 将临时的 ClassLoader 置为 null,它主要用于 AOP
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
// 冻结底层 BeanFactory 容器所有的 BeanDefinition,目的是不希望再去修改 BeanDefinition
beanFactory.freezeConfiguration();
// 【重点】初始化所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式),依赖查找
beanFactory.preInstantiateSingletons();
}
我们看到最后一步,会调用 DefaultListableBeanFactory 的 preInstantiateSingletons() 方法,初始化所有还未初始化的 Bean(不是抽象、单例模式、不是懒加载方式),依赖查找
preInstantiateSingletons 方法
DefaultListableBeanFactory#preInstantiateSingletons() 方法,如下:
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 复制一份本地的所有 beanNames 集合
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// 遍历所有的 beanName
for (String beanName : beanNames) {
// 从容器中获取 beanName 相应的 RootBeanDefinition 对象
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 如果该 Bean 的定义为:不是抽象、单例模式、不是懒加载方式,则进行初始化
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 如果是 FactoryBean 类型的 Bean
if (isFactoryBean(beanName)) {
// 初始化 FactoryBean 类型本身这个 Bean,注意这里在 beanName 的前面添加了一个 '&'
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 如果这个 FactoryBean 为 SmartFactoryBean 类型,并且需要提前初始化
// 则初始 beanName 对应的 Bean,也就是调用 FactoryBean 的 getObject() 方法
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
// 初始化 beanName 对应的 Bean
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
首先会遍历所以的 beanName,如果该 Bean 的定义满足下面三个条件,则进行初始化过程
- 不是抽象
- 单例模式
- 不是懒加载方式
实际就是通过 getBean(String beanName) 方法进行初始化,在前面的 《开启 Bean 的加载》 等文章中已经分析过了。注意,如果是 FactoryBean 类型的 Bean,需要先初始化 FactoryBean 本身这个 Bean,beanName 前面加 &,然后再初始化这个 beanName,也就是调用 FactoryBean#getObject() 方法
在初始化所有的 Bean 后,其实还有一个初始化完成阶段,会遍历所有已初始化好的 Bean,如果是 SmartInitializingSingleton 类型,则调用这个 Bean 的 afterSingletonsInstantiated() 方法
SmartInitializingSingleton 的作用?
通过 getBean(beanName) 初始化一个 Bean 的时候也会初始化依赖的对象,这样可能会出现过早的初始化问题(例如可能有些 BeanPostProcessor 还未添加进来就初始化了),导致相关 Bean 可能还未完全初始化,Spring 4.1 之后就提供了 SmartInitializingSingleton 接口机制让你可以确保 Bean 的初始化行为比较正常。
还有就是在所有的 Bean 完成初始化后,可以在这里进行注解的相关处理,例如 @EventListener 注解就是通过 EventListenerMethodProcessor 实现的,会将@EventListener 注解标注的方法解析成 ApplicationListener 事件监听器,并注册至 Spring 应用上下文。
11. 应用上下文刷新完成阶段
AbstractApplicationContext#finishRefresh() 方法,如下:
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
// 清除当前 Spring 应用上下文中的缓存,例如通过 ASM(Java 字节码操作和分析框架)扫描出来的元数据
clearResourceCaches();
// Initialize lifecycle processor for this context.
// 初始化 LifecycleProcessor 到当前上下文的属性中
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
// 通过 LifecycleProcessor 启动 Lifecycle 生命周期对象
getLifecycleProcessor().onRefresh();
// 发布 ContextRefreshedEvent 事件,会通过事件广播器进行广播,可通过自定义监听器在当前 Spring 应用上下文初始化完后进行相关操作
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
// 如果当前 Spring 应用上下文的 Environment 环境中配置了 'spring.liveBeansView.mbeanDomain'
// 则向 MBeanServer(JMX 代理层的核心)托管 Live Beans,也就是让 Spring Bean 桥接到 MBeanServer
LiveBeansView.registerApplicationContext(this);
}
主要做以下事情:
- 清除当前 Spring 应用上下文中的缓存,例如通过 ASM(Java 字节码操作和分析框架)扫描出来的元数据
- 初始化 LifecycleProcessor 到当前上下文的属性中
- 通过 LifecycleProcessor 启动 Lifecycle 生命周期对象
- 发布 ContextRefreshedEvent 上下文刷新完成事件,会通过事件广播器进行广播
- 如果当前 Spring 应用上下文的 Environment 环境中配置了 spring.liveBeansView.mbeanDomain,则向 MBeanServer(JMX 代理层的核心)托管 Live Beans,也就是让 Spring Bean 桥接到 MBeanServer
总结
ApplicationContext 就是大名鼎鼎的 Spring 应用上下文,底层 IoC 容器就是 DefaultListableBeanFactory 这个类,在它的基础上提供出更多的高级功能,更加适用于正式的应用环境。子类 AbstractApplicationContext 抽象类实现了大部分功能,调用它的 refresh() 方法可以让 Spring 应用上下文处于准备就绪状态,使用 Spring 都会显示或者隐式地调用该方法,这个方法中有非常多核心的步骤,这些步骤在上面的每个小节中依次进行分析过,具体过程可查看上面的每个小节。
AbstractApplicationContext#refresh() 方法在哪被调用?
可以看到我的另一篇文章《精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化》,在 Spring MVC 启动过程中,创建 Spring 应用上下文后,(在 ContextLoader#configureAndRefreshWebApplicationContext 方法中)会调用其 refresh() 方法进行刷新,让 Spring 应用上下文准备就绪。
至此,Spring IoC 的相关内容差不多都讲完了,关于 @Bean 等注解的处理在下一篇文章中进行分析。
相关推荐
- js向对象中添加元素(对象,数组) js对象里面添加元素
-
一、添加一个元素对象名["属性名"]=值(值:可以是一个值,可以是一个对象,也可以是一个数组)这样添加进去的元素,就是一个值或对象或数组...
- JS小技巧,如何去重对象数组?(一)
-
大家好,关于数组对象去重的业务场景,想必大家都遇到过类似的需求吧,这对这样的需求你是怎么做的呢。下面我就先和大家分享下如果是基于对象的1个属性是怎么去重实现的。方法一:使用.filter()和....
- 「C/C++」之数组、vector对象和array对象的比较
-
数组学习过C语言的,对数组应该都不会陌生,于是这里就不再对数组进行展开介绍。模板类vector模板类vector类似于string,也是一种动态数组。能够在运行阶段设置vector对象的长度,可以在末...
- 如何用sessionStorage保存对象和数组
-
背景:在工作中,我将[{},{}]对象数组形式,存储到sessionStorage,然后ta变成了我看不懂的形式,然后我想取之用之,发现不可能了~记录这次深刻的教训。$clickCouponIndex...
- JavaScript Array 对象 javascript的array对象
-
Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...
- JavaScript中的数组Array(对象) js array数组
-
1:数组Array:-数组也是一个对象-数组也是用来存储数据的-和object不同,数组中可以存储一组有序的数据,-数组中存储的数据我们称其为元素(element)-数组中的每一个元素都有一...
- 数组和对象方法&数组去重 数组去重的5种方法前端
-
列举一下JavaScript数组和对象有哪些原生方法?数组:arr.concat(arr1,arr2,arrn);--合并两个或多个数组。此方法不会修改原有数组,而是返回一个新数组...
- C++ 类如何定义对象数组?初始化数组?linux C++第43讲
-
对象数组学过C语言的读者对数组的概念应该很熟悉了。数组的元素可以是int类型的变量,例如int...
- ElasticSearch第六篇:复合数据类型-数组,对象
-
在ElasticSearch中,使用JSON结构来存储数据,一个Key/Value对是JSON的一个字段,而Value可以是基础数据类型,也可以是数组,文档(也叫对象),或文档数组,因此,每个JSON...
- 第58条:区分数组对象和类数组对象
-
示例设想有两个不同类的API。第一个是位向量:有序的位集合varbits=newBitVector;bits.enable(4);bits.enable([1,3,8,17]);b...
- 八皇后问题解法(Common Lisp实现)
-
如何才能在一张国际象棋的棋盘上摆上八个皇后而不致使她们互相威胁呢?这个著名的问题可以方便地通过一种树搜索方法来解决。首先,我们需要写一个函数来判断棋盘上的两个皇后是否互相威协。在国际象棋中,皇后可以沿...
- visual lisp修改颜色的模板函数 怎么更改visual studio的配色
-
(defunBF-yansemokuai(tuyuanyanse/ss)...
- 用中望CAD加载LISP程序技巧 中望cad2015怎么加载燕秀
-
1、首先请加载lisp程序,加载方法如下:在菜单栏选择工具——加载应用程序——添加,选择lisp程序然后加载,然后选择添加到启动组。2、然后是添加自定义栏以及图标,方法如下(以...
- 图的深度优先搜索和广度优先搜索(Common Lisp实现)
-
为了便于描述,本文中的图指的是下图所示的无向图。搜索指:搜索从S到F的一条路径。若存在,则以表的形式返回路径;若不存在,则返回nil。...
- 两个有助于理解Common Lisp宏的例子
-
在Lisp中,函数和数据具有相同的形式。这是Lisp语言的一个重大特色。一个Lisp函数可以分析另一个Lisp函数;甚至可以和另一个Lisp函数组成一个整体,并加以利用。Lisp的宏,是实现上述特色的...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- patch补丁 (31)
- strcat (25)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- element style (30)
- dedecms模版 (53)
- vs打不开 (29)
- nmap (30)
- webgl开发 (24)
- parse (24)
- c 视频教程下载 (33)
- android 开发环境 (24)
- paddleocr (28)
- listview排序 (33)
- firebug 使用 (31)
- transactionmanager (30)
- characterencodingfilter (33)
- getmonth (34)
- commandtimeout (30)
- hibernate教程 (31)
- label换行 (33)