开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第29天,点击查看活动详情
一、ApplicationContextInitializer:在上下文准备阶段,容器刷新之前做一些初始化工作
用于ConfigurableApplicationContext通过调用refresh函数来初始化Spring容器之前的回调函数,通常在web应用中,设计在初始化Spring容器之前调用。例如依赖于容器ConfigurableApplicationContext中的Enviroment来记录一些配置信息或者使一些配置文件生效。
定义
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C var1);
}
实现
public class DemoApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext context) {
System.err.println("----" + this.getClass().getSimpleName());
}
}
二、几个context的继承关系
AnnotationConfigApplicationContext 继承了 GenericApplicationContext 继承了 AbstractApplicationContext 实现了 ConfigurableApplicationContext 继承了 ApplicationContext。
三、AnnotationConfigApplicationContext
AnnotationConfigApplicationContext继承了GenericApplicationContext,就继承了这个通用应用上下文,GenericApplicationContext内部定义了一个DefaultListableBeanFactory实例,GenericApplicationContext实现了BeanDefinitionRegistry接口,所以可以通过AnnotationConfigApplicationContext实例注册beanDefintion,然后调用refresh() 方法来初始化上下文。AnnotationConfigApplicationContext继承AbstractApplicationContext,AbstractApplicationContext提供了ApplicationContext的抽象实现。
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtensionConfig.class);
AnnotationConfigApplicationContext的构造函数主要是创建了Bean定义的读取器和扫描器,然后注册指定的配置类,然后对spring容器进行刷新。
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
//默认构造器
public AnnotationConfigApplicationContext() {
//在IOC容器中初始化一个 注解bean读取器AnnotatedBeanDefinitionReader
this.reader = new AnnotatedBeanDefinitionReader(this);
//在IOC容器中初始化一个 按类路径扫描注解bean的 扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
super(beanFactory);
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
//1. 初始化bean读取器和扫描器;
//调用父类GenericApplicationContext无参构造函数,初始化一个BeanFactory: DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory()
this();
//2.注册bean配置类
this.register(componentClasses);
//3.刷新上下文
this.refresh();
}
register(annotatedClasses)
注册bean配置类, AnnotationConfigApplicationContext容器通过AnnotatedBeanDefinitionReader的register方法实现注解bean的读取,具体源码如下: AnnotationConfigApplicationContext.java中register方法
//按指定bean配置类读取bean
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
//核心实现逻辑
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
//将Bean配置类信息转成容器中AnnotatedGenericBeanDefinition数据结构, AnnotatedGenericBeanDefinition继承自BeanDefinition作用是定义一个bean的数据结构,下面的getMetadata可以获取到该bean上的注解信息
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
//@Conditional装配条件判断是否需要跳过注册
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//@param instanceSupplier a callback for creating an instance of the bean
//设置回调
abd.setInstanceSupplier(instanceSupplier);
//解析bean作用域(单例或者原型),如果有@Scope注解,则解析@Scope,没有则默认为singleton
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
//作用域写回BeanDefinition数据结构, abd中缺损的情况下为空,将默认值singleton重新赋值到abd
abd.setScope(scopeMetadata.getScopeName());
//生成bean配置类beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//通用注解解析到abd结构中,主要是处理Lazy, primary DependsOn, Role ,Description这五个注解
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
//@param qualifiers specific qualifier annotations to consider, if any, in addition to qualifiers at the bean class level
// @Qualifier特殊限定符处理,
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
// 如果配置@Primary注解,则设置当前Bean为自动装配autowire时首选bean
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
//设置当前bean为延迟加载
abd.setLazyInit(true);
}
else {
//其他注解,则添加到abd结构中
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
//自定义bean注册,通常用在applicationContext创建后,手动向容器中一lambda表达式的方式注册bean,
//比如:applicationContext.registerBean(UserService.class, () -> new UserService());
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
//自定义bean添加到BeanDefinition
customizer.customize(abd);
}
//根据beanName和bean定义信息封装一个beanhold,heanhold其实就是一个 beanname和BeanDefinition的映射
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//创建代理对象
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// BeanDefinitionReaderUtils.registerBeanDefinition 内部通过DefaultListableBeanFactory.registerBeanDefinition(String beanName, BeanDefinition beanDefinition)按名称将bean定义信息注册到容器中,
// 实际上DefaultListableBeanFactory内部维护一个Map<String, BeanDefinition>类型变量beanDefinitionMap,用于保存注bean定义信息(beanname 和 beandefine映射)
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
register方法重点完成了bean配置类本身的解析和注册,处理过程可以分为以下几个步骤:
- 根据bean配置类,使用BeanDefinition解析Bean的定义信息,主要是一些注解信息
- Bean作用域的处理,默认缺少@Scope注解,解析成单例
- 借助AnnotationConfigUtils工具类解析通用注解
- 将bean定义信息已beanname,beandifine键值对的形式注册到ioc容器中
refresh()刷新上下文
refresh方法在AbstractApplicationContext容器中实现,refresh()方法的作用加载或者刷新当前的配置信息,如果已经存在spring容器,则先销毁之前的容器,重新创建spring容器,载入bean定义,完成容器初始化工作,debug进源码可以看出AnnotationConfigApplicationContext容器是通过调用其父类AbstractApplicationContext的refresh()函数启动整个IoC容器完成对Bean定义的载入。
AbstractApplicationContext.java中refresh方法的实现代码如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//1.刷新上下文前的预处理
prepareRefresh();
//2.获取刷新后的内部Bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//3.BeanFactory的预准备工作
prepareBeanFactory(beanFactory);
try {
// BeanFactory准备工作完成后,可以做一些后置处理工作,
// 4.空方法,用于在容器的子类中扩展
postProcessBeanFactory(beanFactory);
// 5. 执行BeanFactoryPostProcessor的方法,BeanFactory的后置处理器,在BeanFactory标准初始化之后执行的
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册BeanPostProcessor(Bean的后置处理器),用于拦截bean创建过程
registerBeanPostProcessors(beanFactory);
// 7. 初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
initMessageSource();
// 8. 初始化事件派发器
initApplicationEventMulticaster();
// 9.空方法,可以用于子类实现在容器刷新时自定义逻辑
onRefresh();
// 10. 注册时间监听器,将所有项目里面的ApplicationListener注册到容器中来
registerListeners();
// 11. 初始化所有剩下的单实例bean,单例bean在初始化容器时创建,原型bean在获取时(getbean)时创建
finishBeanFactoryInitialization(beanFactory);
// 12. 完成BeanFactory的初始化创建工作,IOC容器就创建完成;
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
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...
resetCommonCaches();
}
}
}
四、GenericApplicationContext
GenericApplicationContext继承AbstractApplicationContext实现ConfigurableApplicationContext。 GenericApplicationContext通用应用程序上下文实现,该实现内部有一个 DefaultListableBeanFactory 实例。可以采用混合方式处理bean的定义,而不是采用特定的bean定义方式来创建bean。
GenericApplicationContext基本就是对DefaultListableBeanFactory 做了个简易的封装,几乎所有方法都是使用了DefaultListableBeanFactory的方法去实现。
GenericApplicationContext更多是作为一个通用的上下文(通用的IOC容器) 而存在,BeanFactory本质上也就是一个IOC容器,一个用来生产和获取beans的工厂。
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("mybean", MyBean.class);
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.registerBean(ConfigurationClassPostProcessor.class);
//执行顺序: 1. beanFactory 后处理器, 2. 添加 bean 后处理器, 3. 初始化单例
context.refresh();
context.close();
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
//内部的beanFactory
private final DefaultListableBeanFactory beanFactory;
@Nullable
private ResourceLoader resourceLoader;
private boolean customClassLoader = false;
private final AtomicBoolean refreshed = new AtomicBoolean();
/**
* Create a new GenericApplicationContext
初始化一个BeanFactory
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
//......
五、ConfigurableApplicationContext解析
ConfigurableApplicationContext 继承了 ApplicationContext;该接口的主要任务就是配置应用程序上下文功能。
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
//硬性基础属性配置
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
String ENVIRONMENT_BEAN_NAME = "environment";
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";
//给应用上下文-容器设置唯一的id
void setId(String var1);
//设置父容器
void setParent(@Nullable ApplicationContext var1);
//为上下文设置环境变量
void setEnvironment(ConfigurableEnvironment var1);
//获取环境变量配置信息
ConfigurableEnvironment getEnvironment();
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor var1);
void addApplicationListener(ApplicationListener<?> var1);
void setClassLoader(ClassLoader var1);
void addProtocolResolver(ProtocolResolver var1);
void refresh() throws BeansException, IllegalStateException;
void registerShutdownHook();
void close();
boolean isActive();
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
六、ApplicationContext
- 从ListableBeanFactory接口继承来的:用于访问应用组件的工厂方法,直接父接口对BeanFactory进行很多拓展
- 从ResourceLoader接口继承来的:用通用的方式加载文件资源
- 从ApplicationEventPublisher接口继承来的:注册和发布事件
- 从MessageSource接口继承来的:处理消息,支持国际化
- ApplicationContext 还继承了 EnvironmentCapable、HierarchicalBeanFactory、ResourcePatternResolver等接口
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
/**
* 返回一个唯一的应用上下文id
* @return the unique id of the context, or {@code null} if none
*/
@Nullable
String getId();
/**
* 返回已经部署的该应用上下文的名称.
* @return a name for the deployed application, or the empty String by default
*/
String getApplicationName();
/**
* 返回此上下文友好的名称---这有什么用呢?
* @return a display name for this context (never {@code null})
*/
String getDisplayName();
/**
* 返回该上下文第一次被加载的时间戳
* @return the timestamp (ms) when this context was first loaded
*/
long getStartupDate();
/**
*返回父应用上下文, 如果没有父上下文,该上下文就是在上下文层次的根
* @return the parent context, or {@code null} if there is no parent
*/
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}