Spring Boot -- 启动流程分析之ApplicationContext 上
目录
我们总经常听说Spring容器,那Spring容器到底是什么,在介绍创建Spring应用程序上下文之前,我们先来聊一聊Spring容器到底是什么。
一、容器简介
容器顾名思义就是用来装东西的,装的是什么?装的是Bean。
Bean是Spring的基本单位,在基于Spring的web应用中,所有的组件都被当做Bean处理、包括数据源、Hiberate的SessionFactory、事务管理器等。在Spring中,Bean是一个非常广义的概念,任何Java对象,Java组件都被当做Bean处理。
那容器仅仅是用来保存Bean这么简单么?不是。
当我们需要某个Bean时,容器会自动帮我们创建,并在适当时销毁。当某个 Bean 中需创建另一个 Bean 时,也就是 Bean 之间有依赖关系,这种依赖的 Bean 也是由容器自动创建。在外界有一个标准的名词,前者称呼为 IOC,也就是控制反转,后者称呼为 DI,也就是依赖注入。
1.1、IOC/DI
IOC (Inversion of Control) 控制反转:所谓控制反转,就是当我们需要某个 Bean 时,将 Bean 的名称告知容器,由容器去创建该 Bean,而不是我们手动 new 一个,这里 Bean 创建管理的控制权都交给了容器,所以这是一种控制权的反转。其通俗点讲就是需要什么东西让别人送过来,而不是自己去拿。
DI (Dependency Injection) 依赖注入:就是指当 A Bean 里面需创建 B Bean 时,会在创建 A Bean 的时候,自动将依赖的 B Bean 注入进去,其 B Bean 是被动接受注入而不是自己主动去找。换句话说就是指 A Bean 不是从容器中查找它依赖的 B Bean,而是在容器创建 A Bean 候主动将它依赖的 B Bean 注入给它。
IOC 和 DI 其实归根结底实现的功能是相同的,只是同样的功能站在不同的角度来阐述罢了。当然,在真实场景中,交由 Spring 容器创建的 Bean 泛指在应用程序中的表现层、业务层、持久层等各层对应的 Bean,如 Controller、Service 等;进行数据交互的模型,如 DTO、VO 等就不需交由 Spring 来创建。
所以,容器本质上可以也可以看作是 Bean 工厂,该工厂管理 Bean 的生命周期,以及 Bean 之间的依赖关系。外界也将 Spring 容器称为 IOC 容器。当然,这里容器仅仅是 Spring 的抽象概念,代码中将其具象化为 BeanFactory 或 ApplicationContext,容器功能也由具象化的类进行处理。
1.2、容器的结构
容器的实现类并不是唯一的,Spring 框架提供了多个容器的实现,这些容器分为两套体系:一套是早期的 BeanFactory 体系;还有一套是现在常用的 ApplicationContext,也可称为应用上下文,它继承了 BeanFactory,它除了有 BeanFactory 的功能外 ,还提供了其他服务,例如事务和 AOP 服务、国际化(il8n)的消息源以及应用程序事件处理等企业级的服务。
说到这,就不得不说 Spring 的两种配置方式,在早期都是 XML 配置文件的方式,而现在使用的是注解配置的方式。BeanFactory 体系的容器一般用来处理 XML 配置文件的方式,而 ApplicationContext 体系则都可以处理。
下表列出了BeanFactory 和 ApplicationContext 接口和实现所提供的功能:
功能/特点 | BeanFactory | ApplicationContext |
Bean 实例化/装配 | 有 | 有 |
BeanPostProcessor 自动注册 | 没有 | 有 |
BeanFactoryPostProcessor 自动注册 | 没有 | 有 |
MessageSource 便捷访问(针对i18n) | 没有 | 有 |
ApplicationEvent 发布 | 没有 | 有 |
两者还有一个区别是:
- ApplicationContext 在容器启动时,一次性创建了所有的 Bean。
- BeanFactory 在容器启动时,并未创建 Bean,直到第一次访问某个 Bean 时才创建目标 Bean。
1.3、BeanFactory
BeanFactory 是容器最基础的类,它定义了容器的基本功能规范:
public interface BeanFactory {
// 对 FactoryBean 的转义定义,因为如果使用 bean 的名字检索 FactoryBean 得到的对象是工厂生成的对象,
// 如果需要得到工厂本身,需要转义(FactoryBean 在后续会详细介绍)
String FACTORY_BEAN_PREFIX = "&";
// 根据 bean 的名字,获取在容器中 bean 实例
Object getBean(String name) throws BeansException;
//根据 bean 的名字和 Class 类型来得到 bean 实例,增加了类型安全验证机制。
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 提供对 bean 的检索,看看是否在容器有这个名字的 bean
boolean containsBean(String name);
// 根据 bean 名字,判断这个 bean 是不是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 根据 bean 名字,判断这个 bean 是不是原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 根据 bean 名字,判断是否与指定的类型匹配
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
// 得到 bean 实例的 Class 类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 得到bean 的别名,如果根据别名检索,那么其原名也会被检索出来
String[] getAliases(String name);
}
在 BeanFactory 里只对容器的基本行为作了定义,其根本不关心你的 Bean 是如何定义怎样加载的。 正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。而要知道工厂是如何产生对象的,我们就需要看具体的容器了,也就是 BeanFactory 的子类。
BeanFactory 大致的继承关系如下:
BeanFactory 体系中常用的实现类有:
- ListableBeanFactory:提供容器中 bean 迭代的功能。如返回所有 Bean 的名字、容器中 Bean 的数量等。
- HierarchicalBeanFactory:提供父容器的访问功能,可通过 ConfigurableBeanFactory 的 setParentBeanFactory 方法设置父容器。
- AutowireCapableBeanFactory:为 Spring 容器之外的 Bean ,也就是未交由 Spring 管理的 Bean ,提供依赖注入的功能。
以上三个是 BeanFactory 的直系亲属,这个三个直系亲属下面又派生了两个复杂的容器:
- ConfigurableBeanFactory:其继承了 HierarchicalBeanFactory 和 SingletonBeanRegistry 这两个接口,其提供了很多方法,如:定义类加载器、类型转化、属性编辑器、注册依赖 Bean 、销毁 bean 等,且该接口被大多数的容器继承、实现。
- ConfigurableListableBeanFactory:这个接口继承了 ListableBeanFactory、 AutowireCapableBeanFactory、ConfigurableBeanFactory,自身主要提供用于分析和修改 bean 定义以及预先实例化单例 Bean 的方法。
最后是核心容器:
DefaultListableBeanFactory:它实现了以上所有的接口,在 BeanFactory 体系中可以作为一个独立的容器使用。这个类特别重要,后面我们介绍到的Spring应用上下文启动都是围绕该类展开的,这个类中有几个字段我们后面会反复使用到:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
/** Map from serialized id to factory instance. */
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
new ConcurrentHashMap<>(8);
/** Optional id for this factory, for serialization purposes. */
@Nullable
private String serializationId;
/** Whether to allow re-registration of a different definition with the same name. */
private boolean allowBeanDefinitionOverriding = true;
/** Whether to allow eager class loading even for lazy-init beans. */
private boolean allowEagerClassLoading = true;
/** Optional OrderComparator for dependency Lists and arrays. */
@Nullable
private Comparator<Object> dependencyComparator;
/** Resolver to use for checking if a bean definition is an autowire candidate. */
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
/** Map from dependency type to corresponding autowired value. */
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
/** Map of singleton-only bean names, keyed by dependency type. */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
/** List of names of manually registered singletons, in registration order. */
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
/** Cached array of bean definition names in case of frozen configuration. */
@Nullable
private volatile String[] frozenBeanDefinitionNames;
/** Whether bean definition metadata may be cached for all beans. */
private volatile boolean configurationFrozen = false;
...
}
此外还有继承自DefaultSingletonBeanRegistry的字段:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** List of suppressed Exceptions, available for associating related causes. */
@Nullable
private Set<Exception> suppressedExceptions;
/** Flag that indicates whether we're currently within destroySingletons. */
private boolean singletonsCurrentlyInDestruction = false;
/** Disposable bean instances: bean name to disposable instance. */
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
/** Map between containing bean names: bean name to Set of bean names that the bean contains. */
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
/** Map between dependent bean names: bean name to Set of dependent bean names. */
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
/** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
...
}
下面重点介绍一下ApplicationContext,主要是因为ApplicationContext 包含了 BeanFactory,实际中基本不单独使用 BeanFactory。
1.4、ApplicationContext
上面说过 ApplicationContext 是 BeanFactory 子类,它不仅包含 BeanFactory 所有功能,还对其进行了扩展,而我们喜欢将 ApplicationContext 称为应用上下文,因为容器只是它的基本功能。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// 返回此应用程序上下文的唯一ID
@Nullable
String getId();
// 返回此上下文所属的应用程序名称
String getApplicationName();
// 返回应用上下文具像化的类名
String getDisplayName();
// 返回第一次加载此上下文时的时间戳
long getStartupDate();
// 获取父级应用上下文
@Nullable
ApplicationContext getParent();
// 将 AutowireCapableBeanFactory 接口暴露给外部使用
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
ApplicationContext 自身提供的方法非常简单,但它继承了六个接口,来扩展自身功能:
- EnvironmentCapable:获取 Environment。
- ListableBeanFactory、HierarchicalBeanFactory:这是 BeanFactory 体系接口,分别提供 Bean 迭代和访问父容器的功能。
- MessageSource:支持国际化功能。
- ApplicationEventPublisher:应用事件发布器,封装事件发布功能的接口。
- ResourcePatternResolver:该接口继承至 ResourceLoader ,作用是加载多个 Resource。
ApplicationContext 同样提供了非常多的实现类,其又可细分为两大类, ConfigurableApplicationContext 和 WebApplicationContext。
1.5、ConfigurableApplicationContext
该接口是比较重要的一个接口,几乎所有的应用上下文都实现了该接口。该接口在ApplicationContext的基础上提供了配置应用上下文的能力,此外提供了生命周期的控制能力。
public
interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
// 应用上下文配置时,这些符号用于分割多个配置路径
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
// BeanFactory中,ConversionService类所对应的bean的名字。如果没有此类的实例的话吗,则使用默认的转换规则
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
//LoadTimeWaver类所对应的Bean在容器中的名字。如果提供了该实例,上下文会使用临时的 ClassLoader ,这样,LoadTimeWaver就可以使用bean确切的类型了
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
// Environment 类在容器中实例的名字
String ENVIRONMENT_BEAN_NAME = "environment";
// System 系统变量在容器中对应的Bean的名字
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
// System 环境变量在容器中对应的Bean的名字
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
// 设置容器的唯一ID
void setId(String id);
// 设置此容器的父容器
void setParent(@Nullable ApplicationContext parent);
// 设置容器的 Environment 变量
void setEnvironment(ConfigurableEnvironment environment);
// 以 ConfigurableEnvironment 的形式返回此容器的环境变量。以使用户更好的进行配置
@Override
ConfigurableEnvironment getEnvironment();
// 此方法一般在读取应用上下文配置的时候调用,用以向此容器中增加BeanFactoryPostProcessor。增加的Processor会在容器refresh的时候使用。
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
// 向容器增加一个 ApplicationListener,增加的 Listener 用于发布上下文事件,如 refresh 和 shutdown 等
void addApplicationListener(ApplicationListener<?> listener);
// 向容器中注入给定的 Protocol resolver
void addProtocolResolver(ProtocolResolver resolver);
// 这是初始化方法,因此如果调用此方法失败的情况下,要将其已经创建的 Bean 销毁。
// 换句话说,调用此方法以后,要么所有的Bean都实例化好了,要么就一个都没有实例化
void refresh() throws BeansException, IllegalStateException;
// 向JVM注册一个回调函数,用以在JVM关闭时,销毁此应用上下文
void registerShutdownHook();
// 关闭此应用上下文,释放其所占有的所有资源和锁。并销毁其所有创建好的 singleton Beans
@Override
void close();
// 检测此 FactoryBean 是否被启动过
boolean isActive();
// 返回此应用上下文的容器。
// 千万不要使用此方法来对 BeanFactory 生成的 Bean 做后置处理,因为单例 Bean 在此之前已经生成。
// 这种情况下应该使用 BeanFactoryPostProcessor 来在 Bean 生成之前对其进行处理
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
该接口下又有几个重要的实现类:
- AbstractApplicationContext:这是个抽象类,仅实现了公共的上下文特性。这个抽象类使用了模板方法设计模式,需要具体的实现类去实现这些抽象的方法。
- GenericApplicationContext:该类继承自 AbstractApplicationContext,是为通用目的设计的,它能加载各种配置文件,例如 xml,properties 等等。它的内部持有一个 DefaultListableBeanFactory 的实例,实现了 BeanDefinitionRegistry 接口,以便允许向其应用任何 bean 的定义的读取器。
- AnnotationConfigApplicationContext:该类继承自 GenericApplicationContext ,提供了注解配置(例如:@Configuration、@Component等)和类路径扫描(scan方法)的支持。
1.6、WebApplicationContext
该接口是专门为 Web 应用准备的,其允许从相对于 Web 根目录的路径中装载配置文件完成初始化。
public interface WebApplicationContext extends ApplicationContext {
// 整个 Web 应用上下文是作为属性放置在 ServletContext 中的,该常量就是应用上下文在 ServletContext 属性列表中的 key
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
// 定义了三个作用域的名称
String SCOPE_REQUEST = "request";
String SCOPE_SESSION = "session";
String SCOPE_APPLICATION = "application";
// 在工厂中的 bean 名称
String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
// ServletContext 初始化参数名称
String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
// 在工厂中 ServletContext 属性值环境bean的名称
String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
// 用来获取 ServletContext 对象
@Nullable
ServletContext getServletContext();
}
该接口的核心实现类有:
- ConfigurableWebApplicationContext:该接口同时继承了 WebApplicationContext 和 ConfigurableApplicationContext,提供了 Web 应用上下文的可配置的能力。
- GenericWebApplicationContext:该类继承自 GenericApplicationContext,实现了 ConfigurableWebApplicationContext。
- XmlWebApplicationContext:该上下文是使用 Xml 配置文件的方式,不过是在 Web 环境中使用的。
- AnnotationConfigServletWebServerApplicationContext:该类是被 SpringBoot 扩展而来的,SpringBoot 使用的就是该上下文。
二、创建Spring应用上下文(createApplicationContext)
我们接着上一篇博客继续分析SpringApplication run方法中的核心部分代码:应用上下文的创建。
public class SpringApplication {
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
...
private WebApplicationType webApplicationType;
...
public ConfigurableApplicationContext run(String... args) {
...
ConfigurableApplicationContext context = null;
try {
...
// createApplicationContext 方法创建对应的 ApplicationContext 应用上下文
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 该方法实质是启动 Spring 应用上下文的,但 Spring Boot 嵌入式容器也在该过程中被启动,入参是上下文对象
refreshContext(context);
...
}
...
}
...
}
2.1、创建ConfigurableApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 这里就是通过 webApplicationType 属性,判断应用类型,来创建不同的 ApplicationContext 应用上下文
switch (this.webApplicationType) {
case SERVLET:
// 返回的是 Servlet Web ,具体对象为 AnnotationConfigServletWebServerApplicationContext,
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
// 返回的是 Reactive Web,具体对象为 AnnotationConfigReactiveWebServerApplicationContext
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
// 应用类型是非 Web 时,返回 AnnotationConfigApplicationContext
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
...
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
这里也是通过 webApplicationType 属性来确定应用类型从而创建 String 上下文,上篇文章说到该属性值是在 Spring Boot 准备阶段推导出来的。这里我们的应用类型是 Servlet ,所以创建的是 AnnotationConfigServletWebServerApplicationContext 对象。
2.1、AnnotationConfigServletWebServerApplicationContext 构造函数
通过 BeanUtils.instantiateClass会调用AnnotationConfigServletWebServerApplicationContext 的无参构造函数,而在Java的继承中,会先调用父类的构造方法。所以会先调用AnnotationConfigServletWebServerApplicationContext 的父类GeniricApplicationContext的构造方法:
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
@Nullable
private ResourceLoader resourceLoader;
private boolean customClassLoader = false;
private final AtomicBoolean refreshed = new AtomicBoolean();
/**
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
...
}
在父类中初始化beanFactory,即直接new了一个DefaultListableBeanFactory:
/**
* Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs
* to be populated through {@link #register} calls and then manually
* {@linkplain #refresh refreshed}.
*/
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
在构造函数中通过new AnnotatedBeanDefinitionReader(this)实例化了一个Bean读取器:
/**
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
* <p>If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},
* the {@link Environment} will be inherited, otherwise a new
* {@link StandardEnvironment} will be created and used.
* @param registry the {@code BeanFactory} to load bean definitions into,
* in the form of a {@code BeanDefinitionRegistry}
* @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)
* @see #setEnvironment(Environment)
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
/**
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
* using the given {@link Environment}.
* @param registry the {@code BeanFactory} to load bean definitions into,
* in the form of a {@code BeanDefinitionRegistry}
* @param environment the {@code Environment} to use when evaluating bean definition
* profiles.
* @since 3.1
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
最后会调用到AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry registry,Object source)方法:
/**
* Register all relevant annotation post processors in the given registry.
* @param registry the registry to operate on
* @param source the configuration source element (already extracted)
* that this registration was triggered from. May be {@code null}.
* @return a Set of BeanDefinitionHolders, containing all bean definitions
* that have actually been registered by this call
*/
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
这里通过调用registerPostProcessor向BeanDefinitionMap中注册了5个BeanDefinition,BeanDefinition保存 Bean 的相关信息,我们在后面会详细介绍。
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
这里的register就是我们的应用上下文,这里调用的就是GenericApplicationContext的registerBeanDefinition:
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
GenericApplicationContext 底层调用的是 DefaultListableBeanFactory(BeanFactory的实现类)中的实现方法:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
这里注册的BeanDefinition分别为ConfigurationClassPostProcessor、DefaultEventListenerFactory、EventListenerMethodProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor。
接着 调用this.scanner = new ClassPathBeanDefinitionScanner(this)来初始化一个扫描器,这个扫描器在后面扫描包的时候,并没有用到。
三、准备Spring应用上下文(prepareContext)
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
创建完 Spring 应用上下文之后,执行 prepareContext 方法进入准备上下文阶段,我们来看看主要做了哪些操作。
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
3.1、设置Spring 应用上下文的 environment
3.2、Spring 应用上下文后置处理(postProcessApplicationContext)
主要是覆盖当前 Spring 应用上下文默认所关联的 ResourceLoader 和 ClassLoader,以及初始化beanFactory的conversionService。
3.3、类型转换器
为了统一调用Converter进行类型转换,spring为我们提供了一个ConversionService接口。通过实现这个接口我们可以实现自己的Converter调用逻辑:
package org.springframework.core.convert;
import org.springframework.lang.Nullable;
/**
* 类型转换服务
*/
public interface ConversionService {
/**
* 是否支持原类型到目标类型的转换
*/
boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
/**
* 是否支持原类型到目标类型的转换
*/
boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
/**
* 将source实例转成目标类型,如果转换过程出错,抛出 ConversionException,
* 如果 targetType 为null,抛出 IllegalArgumentException
*/
@Nullable
<T> T convert(@Nullable Object source, Class<T> targetType);
/**
* 将source实例转成目标类型,如果转换过程出错,抛出 ConversionException,
* 如果 targetType 为null,抛出 IllegalArgumentException
*/
@Nullable
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}
我们可以看到ConversionService接口里面定义了两个canConvert方法和两个convert方法,canConvert方法用于判断当前的ConversionService是否能够对原类型和目标类型进行转换,convert方法则是用于进行类型转换的。
比如我们想实现String类型到IBaseEnum类型的转换可以怎么办呢,我们可以自己实现一个类型转换器:
package com.goldwind.bigdataplat.core.config;
import com.goldwind.ngsp.auth.api.constant.enums.IBaseEnum;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.stereotype.Component;
import javax.validation.constraints.NotBlank;
/**
* Author: zy
* Description: String->IbaseEnum类型转换器
* Date: 2020/5/21
*/
public class EnumConverterFactory implements ConverterFactory<String, IBaseEnum> {
/**
* @author: zy
* @description: 获取String->targetType类型的转换器 用于支持自己IBaseEnum类型(Spring支持常规的枚举类型)
* @date: 2020/5/21 10:17
* @param targetType: 目标类型
* @return Converter<String,T>:
*/
@Override
public <T extends IBaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
//获取给定类型对应的转换器
return new StrToEnum(targetType);
}
/*
* 整型字符串转换为T枚举类型的转换器
*/
private class StrToEnum<T extends Enum<T> & IBaseEnum> implements Converter<String, T> {
/*
* 保存枚举类型
*/
private final Class<T> enumType;
/*
* 构造函数
*/
private StrToEnum(Class<T> enumType) {
this.enumType = enumType;
}
/*
* 将给定的字符串转换成对应的枚举类型
*/
@Override
public T convert(@NotBlank String source) {
try{
return (T)IBaseEnum.valueOf(this.enumType, Integer.parseInt(source));
}catch(NumberFormatException e) {
return (T)IBaseEnum.valueOf(this.enumType, source);
}
}
}
}
其中IBaseEnum定义如下:

package com.goldwind.ngsp.auth.api.constant.enums;
/**
* Author: zy
* Description: 用户支持将http请求参数中传入的数字转换为对应的枚举值
* Date: 2020/5/21
*/
public interface IBaseEnum{
/*
* 与数据库进行映射的值
*/
int getValue();
/*
* 描述信息
*/
String getDesc();
/*
* 将状态码装换为枚举类型
*/
static <E extends IBaseEnum> IBaseEnum valueOf(Class<E> enumClass,int value){
try {
E[] enumConstants = enumClass.getEnumConstants();
for (E e : enumConstants) {
if (e.getValue() == value)
return e;
}
return null;
} catch (Exception ex) {
throw new IllegalArgumentException("Cannot convert " + value + " to " + enumClass.getSimpleName() + " by code value.", ex);
}
}
/*
* 将枚举字符串装换为枚举类型
*/
static <E extends Enum<E>> IBaseEnum valueOf(Class<E> enumClass,String value) {
return (IBaseEnum) Enum.valueOf(enumClass, value);
}
}
然后,我们采用@Bean注解,将这个类型转换器注入到Spring容器中:
/*
* 注入自定义类型转换器ConversionService
*/
@Bean
public GenericConversionService getDefaultConversionService(@Autowired GenericConversionService conversionService) {
conversionService.addConverterFactory(new EnumConverterFactory());
return conversionService;
}
可以看到这里是拿到了Spring容器中的GenericConversionService对象,然后调用addConverterFactory加入我们的类型转换器工厂。
顾名思义,ConverterRegistry接口就是用来注册各种转换器的:
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.convert.converter;
/**
* For registering converters with a type conversion system.
*
* @author Keith Donald
* @author Juergen Hoeller
* @since 3.0
*/
public interface ConverterRegistry {
/**
* Add a plain converter to this registry.
* The convertible source/target type pair is derived from the Converter's parameterized types.
* @throws IllegalArgumentException if the parameterized types could not be resolved
*/
void addConverter(Converter<?, ?> converter);
/**
* Add a plain converter to this registry.
* The convertible source/target type pair is specified explicitly.
* <p>Allows for a Converter to be reused for multiple distinct pairs without
* having to create a Converter class for each pair.
* @since 3.1
*/
<S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter);
/**
* Add a generic converter to this registry.
*/
void addConverter(GenericConverter converter);
/**
* Add a ranged converter factory to this registry.
* The convertible source/target type pair is derived from the ConverterFactory's parameterized types.
* @throws IllegalArgumentException if the parameterized types could not be resolved
*/
void addConverterFactory(ConverterFactory<?, ?> factory);
/**
* Remove any converters from {@code sourceType} to {@code targetType}.
* @param sourceType the source type
* @param targetType the target type
*/
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}
3.4、执行 Spring 的初始化器ApplicationContextInitializer
上篇文章说过在 Spring Boot 准备阶段初始化了一批在 spring.factories 文件中定义好的 ApplicationContextInitializer ,这里就是执行它们的 initialize 方法,同时向应用上下文beanFactoryPostProcessors列表添加两个对象:
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
/** BeanFactoryPostProcessors to apply on refresh. */
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
3.5、触发ApplicationContextInitializedEvent事件
执行 SpringApplicationRunListeners 的 contextPrepared 阶段方法,表示 ApplicationContext 准备完成,同时向 Spring Boot 监听器发布 ApplicationContextInitializedEvent 事件 。
3.6、注册单例Bean实例
将 springApplicationArguments 和 springBootBanner注册为单例Bean实例,至于为什么注册为单例Bean、可以参考博客:Spring 为啥默认把bean设计成单例的?,Spring对象类型——单例和多例。
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
3.7、加载 Spring 应用上下文的配置源到BeanDefinitionMap
讲SpringApplication准备阶段获取的 primarySources注册到Spring容器 ,primarySources 来源于 SpringApplication 构造器参数;
3.8、触发ApplicationPreparedEvent事件
最后执行 SpringApplicationRunListeners 的 contextLoaded 阶段方法,表示 ApplicationContext 完成加载但还未启动,同时向 Spring Boot 监听器发布 ApplicationPreparedEvent 事件 。
四、刷新Spring应用上下文(refreshContext )
接下来就是真正启动阶段,执行的是 refreshContext 方法:
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
然后调用refresh方法:
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
// 最终调用了 所有应用上下文的统一抽象类 AbstractApplicationContext 中的 refresh 方法,进入
((AbstractApplicationContext) applicationContext).refresh();
}
AbstractApplicationContext 的 refresh 方法如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 初始化 refresh 的上下文环境,就是记录下容器的启动时间、标记已启动状态、处理配置文件中的占位符
prepareRefresh();
// 2. 初始化 BeanFactory,加载并解析配置
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
/* ---至此,已经完成了简单容器的所有功能,下面开始对简单容器进行增强--- */
// 3. 对 BeanFactory 进行功能增强,如设置BeanFactory的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 4. 后置处理 beanFactory,添加后置处理器
postProcessBeanFactory(beanFactory);
// 5. 调用已注册的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessor,仅仅是注册,调用在getBean的时候
registerBeanPostProcessors(beanFactory);
// 7. 初始化国际化资源
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 留给子类实现的模板方法
onRefresh();
// 10. 注册事件监听器
registerListeners();
// 11. 实例化所有非延迟加载的单例
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新过程,发布应用事件
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
}
// 13.销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
this.destroyBeans();
// Reset 'active' flag.
this.cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
this.resetCommonCaches();
}
}
}
4.1、prepareRefresh
我们先从 refresh 中的 prepareRefresh 方法开始讨论:
public class AnnotationConfigServletWebServerApplicationContext
extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
...
@Override
protected void prepareRefresh() {
// 清除 Class 的元数据缓存。底层用 Map 保存元数据,执行 Map 的 clear 方法
this.scanner.clearCache();
// 调用父类,也就是 AbstractApplicationContext 的 prepareRefresh 方法
super.prepareRefresh();
}
...
}
这里调用父类的prepareRefresh方法:
public abstract class AbstractApplicationContext {
...
private long startupDate;
private final AtomicBoolean active = new AtomicBoolean();
private final AtomicBoolean closed = new AtomicBoolean();
private Set<ApplicationEvent> earlyApplicationEvents;
...
protected void prepareRefresh() {
// 记录此上下文开始时的系统时间(以毫秒为单位)
this.startupDate = System.currentTimeMillis();
// 记录此上下文是否已关闭,这里设置为未关闭
this.closed.set(false);
// 记录此上下文是否处于活动状态,这里设置为活动状态
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// 这也是交由子类扩展的方法。具体子类为 GenericWebApplicationContext,主要是初始化属性源,
// 将 ServletContext 和 ServletConfig 属性配置添加到 Environment 环境上下文中
initPropertySources();
// 校验 Environment 中那些必备的属性配置是否存在,不存在则抛异常。
getEnvironment().validateRequiredProperties();
// 创建 ApplicationEvent 事件集合
this.earlyApplicationEvents = new LinkedHashSet<>();
}
}
refresh 中的 prepareRefresh 方法执行结束,主要是记录容器的启动时间、活动状态、检查必备属性是否存在。
4.2、obtainFreshBeanFactory
接着进入 refresh 中的 obtainFreshBeanFactory 方法:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 该方法也是由子类扩展,其子类有 AbstractRefreshableApplicationContext 和 GenericApplicationContext,
// 因当前是 Servlet Web 应用,所以执行的是 GenericApplicationContext 中的 refreshBeanFactory 方法。
// 该方法主要设置 BeanFactory 的 serializationId 属性值,也就是序列化id
refreshBeanFactory();
// 通过 getBeanFactory 返回 BeanFactory 对象。同样也是由子类扩展,调用的是 GenericApplicationContext 类中的 getBeanFactory 方法。
// 返回的是 DefaultListableBeanFactory 。
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
之后,该方法还返回了 BeanFactory 对象,从这也可以看出 ApplicationContext 底层是以 BeanFactory 为基础,逐步扩展 Spring 容器功能。
4.3、prepareBeanFactory
接着进入 refresh 中的 prepareBeanFactory 方法。prepareBeanFactory 方法主要是对 BeanFactory 做一些配置,包含各种类加载器、需要忽略的依赖以及后置处理器、解析器等:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 设置类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置表达式解析器,主要用来解析 EL 表达式; Bean 初始化完成后填充属性时会用到
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 设置属性注册解析器,主要用来解析 Bean 中的各种属性类型,如 String、int 等
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加一个后置处理器:ApplicationContextAwareProcessor。
// 该后置处理器用于向实现了 Aware 系列接口的 bean 设置相应属性。
// (后置处理器和 Aware 接口也是比较核心的概念)
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 需自动注入时,指定其注入的类型 。
// 如:注入 BeanFactory 时,注入的类型对象为 ConfigurableListableBeanFactory 。
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// 添加 ApplicationListenerDetector 后置处理器。
// 该后置处理器用来检测那些实现了 ApplicationListener 接口的 bean,并将其添加到应用上下文的事件广播器上。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 判断容器中是否存在 loadTimeWeaver Bean,如果存在则上下文使用临时的 ClassLoader 进行类型匹配。
// 集成 AspectJ 时会用到 loadTimeWeaver 对象。
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 注册和环境相关的 Bean,如 environment、systemProperties、systemEnvironment
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());
}
}
在 prepareBeanFactory 方法中,主要对 BeanFactory 添加了一系列属性项,如添加忽略自动注入的接口、添加 BeanPostProcessor 后置处理器、手动注册部分特殊的 Bean及环境相关的 Bean,值得注意的是这些Bean都是单例的 ,因此直接保存单例Bean实例。
/**
* Dependency interfaces to ignore on dependency check and autowire, as Set of
* Class objects. By default, only the BeanFactory interface is ignored.
*/
private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();
/** BeanPostProcessors to apply in createBean. */
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
4.4、postProcessBeanFactory
postProcessBeanFactory 方法是上下文准备的最后一步,主要用来注册 Web 请求相关的处理器、Bean及配置。
public class AnnotationConfigServletWebServerApplicationContext
extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();
private String[] basePackages;
...
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 先执行父类 ServletWebServerApplicationContext 的 postProcessBeanFactory 方法。
// 跳转到 1 查看父类实现
super.postProcessBeanFactory(beanFactory);
// basePackages 存储的是类路径。先判断是否为 null,不为 null 则通过 ClassPathBeanDefinitionScanner 的 scan 方法
// 扫描该路径下符合条件的 Class,并将 Class 信息包装成 BeanDefinition 注册到容器中,
// 当然,这里没有指定扫描路径,所以不会进入这个 if。
// (BeanDefinition 概念会在后面章节详细讨论)
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
// annotatedClasses 存储的 Class 集合。先判断该集合是否为空,不为空则通过
// AnnotatedBeanDefinitionReader 的 register 方法将 Class 信息包装成 BeanDefinition 注册到容器中,
// 这里同样没有设置 Class 集合内容,所以不会进入这个 if。
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
}
//1
public class ServletWebServerApplicationContext extends GenericWebApplicationContext
implements ConfigurableWebServerApplicationContext {
...
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 添加 BeanPostProcessor 后置处理器:WebApplicationContextServletContextAwareProcessor,
// 该后置处理器主要是从 ConfigurableWebApplicationContext 上下文中获取 ServletContext 和 ServletConfig 对象
beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
// 添加一个 忽略自动注入的接口
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
...
}
postProcessBeanFactory 方法执行的操作和前面类似,也是添加了后置处理器和忽略自动注入的接口。
五、BeanDefinition
原计划是对接下来的 invokeBeanFactoryPostProcessors 方法进行讨论,但该方法涉及 Spring 中一个非常重要的概念: BeanDefinition,其实上面我们也提到了,只是没有具体的介绍,所以,这里先对 BeanDefinition 进行讨论,这样也有利于完善 Spring 的知识体系。
现如今,我们一般获取对象的方式有两种:
- 一种是手动直接 new;
- 另一种是交给 Spring 管理,Spring 将管理的对象称之为 Bean,容器会先实例化 Bean,然后自动注入,实例化的过程就需要依赖 BeanDefinition。
BeanDefinition 用于保存 Bean 的相关信息,包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载等,它是实例化 Bean 的原材料,Spring 就是根据 BeanDefinition 中的信息实例化 Bean。
BeanDefinition 是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean。
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了