spring在beanFactory的基础上提供了一些具体容器实现
1、AnnotationConfigApplicationContext:是一个用来管理注解bean容器的
2、ClassPathXmlApplicationContext:主要用在在类路径加载xml文件的场景
今天主要介绍AnnotationConfigApplicationContext
- AnnotationConfigApplicationContext继承了GenericApplicationContext这个通用应用上下文,GenericApplicationContext内部定义了一个DefaultListableBeanFactory实例,GenericApplicationContext实现了BeanDefinitionRegistry接口,所以可以通过AnnotationConfigApplicationContext实例注册beanDefinition,然后通过调用refresh()方法来初始化上下文
- AnnotationConfigApplicationContext继承了AbstractApplicationContext,AbstractApplicationContext提供了ApplicationContext的抽象实现
1、下面通过实例演示AnnotationConfigApplicationContext的初始化过程
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
2、AnnotationConfigApplicationContext的构造方法
/**
* 这个构造方法需要传入一个被javaConfig(@Configuration)注解了的配置类
* 然后会把这个被@Configuration注解了的类通过注解读取器读取后继而解析
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given annotated classes and automatically refreshing the context.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
// 这里由于他有父类,故而会先调用父类的构造方法,然后才会调用自己的构造方法
// 在自己的构造方法中初始一个读取器和扫描器
this();// 这里会初始化读取器和扫描器,看下面
register(annotatedClasses);
refresh();
}
/**
* 初始化一个bean的读取器和扫描器
*
* 默认构造函数,如果直接调用这个默认的构造方法,需要在稍后通过调用register()
* 去注册配置类(加了@Configuration注解的类),并调用refresh()方法刷新容器
* 触发器对注解Bean的载入,解析和注册过程
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
/**
* AnnotatedBeanDefinition: 加了注解类的描述
* 创建一个读取注解的Bean定义读取器
* 什么事Bean定义? BeanDefinition
*
* 在IOC容器中初始化一个 注解bean读取器AnnotatedBeanDefinitionReader
*/
this.reader = new AnnotatedBeanDefinitionReader(this);
// 在IOC容器中初始化一个 按类路径扫描注解bean的 扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
3、GenericApplicationContext部分代码:
/**
* 实例化一个工厂
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
4、AnnotationConfigApplicationContext的register(annotatedClasses)是注册bean配置类,实现bean的读取,方法如下走
/**
* 这个构造方法需要传入一个被javaConfig(@Configuration)注解了的配置类
* 然后会把这个被@Configuration注解了的类通过注解读取器读取后继而解析
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given annotated classes and automatically refreshing the context.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
// 这里由于他有父类,故而会先调用父类的构造方法,然后才会调用自己的构造方法
// 在自己的构造方法中初始一个读取器和扫描器
this();
/**
* register方法重点完成了bean配置类本身的解析和注册,处理过程可以分为以下几个步骤:
* 1.根据bean配置类,使用BeanDefinition解析Bean的定义信息,主要是一些注解信息
* 2.Bean作用域的处理,默认缺少@Scope注解,解析成单例
* 3.借助AnnotationConfigUtils工具类解析通用注解
* 4.将bean定义信息已beanname,beandifine键值对的形式注册到ioc容器中
*/
register(annotatedClasses);
refresh();
}
/**
* 注册单个bean给容器
* 比如有新的bean可以用这个方法
* 但是注册之后需要手动调用refresh()方法去出发容器解析注解
*
* 有2个意思
* 1、可以注册一个配置类
* 2、可以单独注册一个bean
* Register one or more annotated classes to be processed.
* <p>Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
* @see #scan(String...)
* @see #refresh()
*/
@Override
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
/**
* Register one or more annotated classes to be processed.
* <p>Calls to {@code register} are idempotent; adding the same
* annotated class more than once has no additional effect.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* @param annotatedClass the class of the bean
*/
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
// 方法的最终实现是在AnnotatedBeanDefinitionReader类中
/**
* register方法重点完成了bean配置类本身的解析和注册,处理过程可以分为以下几个步骤:
* 1.根据bean配置类,使用BeanDefinition解析Bean的定义信息,主要是一些注解信息
* 2.Bean作用域的处理,默认缺少@Scope注解,解析成单例
* 3.借助AnnotationConfigUtils工具类解析通用注解
* 将bean定义信息已beanname,beandifine键值对的形式注册到ioc容器中
*
*
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* @param annotatedClass the class of the bean
* @param instanceSupplier a callback for creating an instance of the bean
* (may be {@code null})
* @param name an explicit name for the bean
* @param qualifiers specific qualifier annotations to consider, if any,
* in addition to qualifiers at the bean class level
* @param definitionCustomizers one or more callbacks for customizing the
* factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
* @since 5.0
*/
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
/**
* 根据指定的bean创建一个AnnotatedGenericBeanDefinition
* 这个AnnotatedGenericBeanDefinition可以理解为一个数据结构
* AnnotatedGenericBeanDefinition主要是用来描述类的注解信息,比如一些元信息
* 如Scope,Lazy,Primary,DependsOn,Role,Description等
*
*/
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
/**
* 判断这个类是否需要跳过解析
* 通过代码可以知道spring判断是否跳过解析,主要判断类有没有加注解
*/
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
/**
* 设置回调
*/
abd.setInstanceSupplier(instanceSupplier);
/**
* 解析bean作用域(单例或者原型),如果有@Scope注解,则解析@Scope,没有则默认为singleton
*/
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
/**
* 把类的作用域添加到AnnotatedGenericBeanDefinition(数据结构中)
*/
abd.setScope(scopeMetadata.getScopeName());
/**
* 生成bean配置类beanName
*/
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
/**
* 处理类当中的通用注解
* 分析源码可以知道他主要处理
* Lazy, primary DependsOn, Role ,Description这五个注解
* 处理完成之后processCommonDefinitionAnnotations中依然是把他添加到数据结构当中
*/
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
/**
* 如果在向容器注册注解Bean定义时,使用了额外的限定符注解则解析
* @Qualifier:注入指定名称的bean;
* @Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
* 这里需要注意的是
* byName和@Qualifier这个变量是Annotaion类型数组,里面存的不仅仅是@Qualifier注解
* 理论上里面存的是一切注解,所以可以看到下面的代码spring去循环这个数组
* 然后依次判断了注解当中是否包含了Primary,是否包含了Lazy
*/
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
// 如果配置了@Primary注解,如果加了则作为首选
if (Primary.class == qualifier) {
// 如果配置@Primary注解,则设置当前Bean为自动装配autowire时首选bean
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
//设置当前bean为延迟加载
abd.setLazyInit(true);
}
else {
// 如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一个根据名字自动装配的限定符
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
/**
* 自定义bean注册,通常用在applicationContext创建后,手动向容器中一lambda表达式的方式注册bean,
* 比如:applicationContext.registerBean(UserService.class, () -> new UserService());
*/
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
//自定义bean添加到BeanDefinition
customizer.customize(abd);
}
/**
* 这个BeanDefinitionHolder也是一个数据结构(底层是个数据)
* key是存放了这个bean的所有元信息
* value存放的是这个bean的beanName
*/
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//创建代理对象
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
/**
* 把上述的这个数据结构注册给registry
* registry就是AnnotationConfigApplicationContext
* AnnotationConfigApplicationContext在初始化的时候通过调用父类的构造方法
* 实例化一个DefaultListableBeanFactory
* registerBeanDefinition里面就是把definitionHolder这个数据结构包含的信息注册到
* DefaultListableBeanFactory这个工厂
*/
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
register方法重点完成了bean配置类本身的解析和注册,处理过程可以分为以下几个步骤:
- 根据bean配置类,使用BeanDefinition解析Bean的定义信息,主要是一些注解信息
- Bean作用域的处理,默认缺少@Scope注解,解析成单例
- 借助AnnotationConfigUtils工具类解析通用注解
- 将bean定义信息已beanname,beandifine键值对的形式注册到ioc容器中
5、refresh()刷新上下文
refresh方法在AbstractApplicationContext容器中实现,refresh()方法的作用加载或者刷新当前的配置信息,如果已经存在spring容器,则先销毁之前的容器,重新创建spring容器,载入bean定义,完成容器初始化工作,所以可以看出AnnotationConfigApplicationContext容器是通过调用其父类AbstractApplicationContext的refresh()函数启动整个IoC容器完成对Bean定义的载入。
// refresh()方法的最终实现是在AbstractApplicationContext类中
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 准备工作包括设置启动时间,是否激活标识位,初始化属性源(propert source)配置
//1.刷新前的预处理
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//2.获取刷新后的内部Bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//3.BeanFactory的预准备工作
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// BeanFactory准备工作完成后,可以做一些后置处理工作,
// 4.空方法,用于在容器的子类中扩展
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 5. 执行BeanFactoryPostProcessor的方法,BeanFactory的后置处理器,
// 在BeanFactory标准初始化之后执行的
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 6. 注册BeanPostProcessor(Bean的后置处理器),用于拦截bean创建过程
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 7. 初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
initMessageSource();
// Initialize event multicaster for this context.
// 8. 初始化事件派发器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 9.空方法,可以用于子类实现在容器刷新时自定义逻辑
onRefresh();
// Check for listener beans and register them.
// 10. 注册时间监听器,将所有项目里面的ApplicationListener注册到容器中来
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 11. 初始化所有剩下的单实例bean,单例bean在初始化容器时创建,
// 原型bean在获取时(getbean)时创建
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 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();
}
}
}
// 重点分析
//1.刷新前的预处理
prepareRefresh();
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Switch to active.
//设置容器启动时间
this.startupDate = System.currentTimeMillis();
//启动标识
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
// 这个方法目前没有子类实现
// 估计spring是期待后面版本有子类实现吧
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<>();
}
// 第2步中
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//为beanfactory生成唯一序列化id,beanfactory已经在GenericApplicationContext构造函数中初始化了,
// refreshBeanFactory的逻辑在AbstractApplicationContext的实现类GenericApplicationContext中
refreshBeanFactory();
//获取beanfactory
return getBeanFactory();
}