
正文
Spring IOC-基于注解配置的容器
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
Spring
中提供了基于注解来配置
bean
的容器,即
AnnotationConfigApplicationContext
1. 开始
先看看在Spring家族中,
AnnotationConfigApplicationContext
在一个什么样的地位,看看继承图
可以看到
Spring
提供了基于
Xml
配置的容器之外,还提供了基于注解和
Groovy
的容器,今天我们来看看基于注解配置的容器
2. 方法窥探
看看
AnnotationConfigApplicationContext
中提供了哪些方法
3. 从构造方法开始
我们从构造方法开始,分析基于注解的容器,是如何获取
BeanDefinition
并注册
beanDefinitionMap
中的
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
接下来一步一步分析下去
this()
调用了本类中的一个无参构造函数
public AnnotationConfigApplicationContext() {
//注解bean读取器
this.reader = new AnnotatedBeanDefinitionReader(this);
//注解bean扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
而
AnnotationConfigApplicationContext
继承自
GenericApplicationContext
,所以
GenericApplicationContext
的无参构造方法也会被调用
/**
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
可以看到父类拆功能键
scan(basePackages)
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
调用了
scanner.scan()
,
scanner
是
ClassPathBeanDefinitionScanner
的一个实例
/**
* Perform a scan within the specified base packages.
* @param basePackages the packages to check for annotated classes
* @return number of beans registered
*/
public int scan(String... basePackages) {
// 原来的beanDefinition数量
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
doScan(basePackages);
// 下面是注册配置处理器
// 这个是啥呢,就是以前在xml中配置的<context:annotation-config>
// 这里会注册四个注解处理器,分别是
// AutowiredAnnotationBeanPostProcessor,
// CommonAnnotationBeanPostProcessor
// PersistenceAnnotationBeanPostProcessor
// RequiredAnnotationBeanPostProcessor
// 这四个都是BeanPostProccessor,在每个Bean创建的时候都会调用它们
// 既然是注解处理器,他们处理什么注解呢?
// AutowiredAnnotationBeanPostProcessor 处理@AutoWired注解
// CommonAnnotationBeanPostProcessor 处理@ Resource 、@ PostConstruct、@ PreDestroy
// PersistenceAnnotationBeanPostProcessor 处理@PersistenceContext
// RequiredAnnotationBeanPostProcessor 处理@Required
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
// 返回本次扫描注册的beanDefinition数量
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
这个
ClassPathBeanDefinitionScanner
是干什么的呢,通过查看源码注释
/ * A bean definition scanner that detects bean candidates on the classpath,
* registering corresponding bean definitions with a given registry ({@code BeanFactory}
* or {@code ApplicationContext}).
*
* <p>Candidate classes are detected through configurable type filters. The
* default filters include classes that are annotated with Spring's
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, or
* {@link org.springframework.stereotype.Controller @Controller} stereotype.
*/
意思就是扫描类路径下的被
@Component
,
@Repository
,
@Service
,
@Controller
注解的的类,然后注册
BeanDefinition
到给定的
BeanFactory
重点戏就在
doScan()
方法中
/**
* Perform a scan within the specified base packages,
* returning the registered bean definitions.
* 扫描指定的包,反正注册后的Bean Definition
* <p>This method does <i>not</i> register an annotation config processor
* but rather leaves this up to the caller.
* 这个方法不会注册注解处理器,而是留给调用者去做这件事
* @param basePackages the packages to check for annotated classes
* @return set of beans registered if any for tooling registration purposes (never {@code null})
*/
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
// 遍历给定的packages
for (String basePackage : basePackages) {
// findCandidateComponents是获取一个包下的满足条件的类,下面会介绍
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
findCandidateComponents(String basePackage)
这个方法可以获取一个包下的满足条件的
BeanDefinition
/**
* Scan the class path for candidate components.
* @param basePackage the package to check for annotated classes
* @return a corresponding Set of autodetected bean definitions
*/
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
// 是否使用Filter,不扫描指定的包
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
// 扫描包
return scanCandidateComponents(basePackage);
}
}
这个
scanCandidateComponents()
里面就是获取资源判断是否满足条件,但是
Spring
判断的条件比较复杂,就先不看了
再回到
doScan()
方法里面:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
// 遍历给定的packages
for (String basePackage : basePackages) {
// findCandidateComponents是获取一个包下的满足条件的类,下面会介绍
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 绑定scope(解析@Scope)
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 设置beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
////检查beanName否存在
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 正式将BeanDefinition注入
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
registerBeanDefinition(definitionHolder,registry)
/**
* Register the specified bean with the given registry.
* <p>Can be overridden in subclasses, e.g. to adapt the registration
* process or to register further bean definitions for each scanned bean.
* @param definitionHolder the bean definition plus bean name for the bean
* @param registry the BeanDefinitionRegistry to register the bean with
*/
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
/**
* Register the given bean definition with the given bean factory.
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
// 以主要名称
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
// 如果有别名,遍历别名注册到容器的aliasMap
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
上面的
registry.registerBeanDefinition()
就是
DefaultListableBeanFactory
中的方法了
现在
scan()
方法已经走完了,回到构造方法中,还剩最后一个
refresh()
refresh()
这里的
refresh
和
Xml
的容器中调用的
refresh
是同一个方法,都来自
AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 记录启动时间,标记状态,检查变量
prepareRefresh();
// 初始化BeanFactory容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 添加BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 子类扩展点
postProcessBeanFactory(beanFactory);
// 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 BeanPostProcessor 的实现类
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource
initMessageSource();
// 初始化事件广播器
initApplicationEventMulticaster();
// 子类扩展点
onRefresh();
// 注册事件监听器
registerListeners();
// 初始化所有的 singleton beans
finishBeanFactoryInitialization(beanFactory);
// 完成refresh(),发布广播事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经初始化的的Bean
destroyBeans();
// 设置 active为false
cancelRefresh(ex);
throw ex;
}
finally {
// 清除缓存
resetCommonCaches();
}
}
}
这里也有一点不同就是第二步
obtainFreshBeanFactory()
,这个方法里面的调用
getBeanFactory
是留给子类实现的,基于注解的
AnnotationConfigApplicationContext
和
ClassPathXmlApplicationContext
是不一样的。
具体就是调用
refresh
方法多次,
AnnotationConfigApplicationContext
类的
BeanFactory
始终都是同一个,不会重新创建,但是
ClassPathXmlApplicationContext
会重新创建






