//BeansContextConfig为我们自定义的包含@Configuration注解的配置类
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(BeansContextConfig.class);
//我们一般通过下面的方式进行Bean对象的获取
Person person1 = (Person) acac.getBean("person");
Person person2 = acac.getBean(Person.class);
下面就开始从源码着手,对IOC容器启动过程的一个简单的认识:
首先我们可以进入AnnotationConfigApplicationContext的构造方法里,可以看到以下的代码块:
public AnnotationConfigApplicationContext(Class>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
这里我们可以一行一行的进行分析:
1、我们先看第一行this()调用自身的无参构造方法,我们可以到这个构造方法里看一下:
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
可以看到这个构造方法只有两行代码,字面意思,AnnotatedBeanDefinitionReader(注解的Bean定义读取器),ClassPathBeanDefinitionScanner(类路径的Bean定义扫描器),看到这里,猜的话感觉像是对Bean定义信息的注册,字面意思都是对Bean定义的获取,我们先不管有没有猜对,接着看源码,依然是一行一行的追踪:
(1)进入到AnnotatedBeanDefinitionReader
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
可以看到一个参数是把我们创建的AnnotationConfigApplicationContext给穿进来了,AnnotationConfigApplicationContext也是BeanDefinitionRegistry的一个实现类,第二个参数是获取或者创建环境变量信息,进去也可以看到是将AnnotationConfigApplicationContext环境变量里的环境变量获取到,如果没有创建一个,并作为第二个参数传入this构造方法里,不过不是我们的主线,所以继续往下走,
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(this.registry);
看方法名就感觉这个方法跟我们的主线有点关系,字面意思注册注解配置的处理器,可能还是不好理解,我们继续往下走,
public static Set registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, 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 beanDefs = new LinkedHashSet(4);
。
。
。
return beanDefs;
}
最终会走到这个方法里,代码比较多,所以就展示了一部分,我们可以看到这个方法里有很多的判断语句,不过可以一目了然的看到,基本都是判断我们创建的AnnotationConfigApplicationContext中是否包含相应后置处理器的Bean定义信息,如果没有的话,会在这个方法里的beanDefs中添加一个在registerPostProcessor方法里返回的后置处理器的Bean定义信息,最后将Bean定义信息的列表返回,我们再返回上一级
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
这里似乎并没有地方接收返回的Bean定义信息的列表,或许通过注解的方式启动容器,不需要接收吧,不过先不管这个,因为我们可以看到在registerPostProcessor方法里传入了我们创建的AnnotationConfigApplicationContext,我们先进来看看:
private static BeanDefinitionHolder registerPostProcessor(
BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(beanName, definition);
return new BeanDefinitionHolder(definition, beanName);
}
可以看到第二行确实是将Bean定义信息给注册到了AnnotationConfigApplicationContext上下文中,所以这一步到这里也就结束了,这一步主要就是将容器内部的后置处理器的Bean定义信息给注册到我们的上下文,也就是IOC容器中。
(2)进入到ClassPathBeanDefinitionScanner
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
在这里同样是把我们创建的AnnotationConfigApplicationContext穿进来,并传了一个true,接着往下走,最终会走到这里:
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
在这里我们可以看到,刚才默认传递进来的true是以useDefaultFilters参数的形式传递过来的,所以必然会走到if判断里,下面的两行,一行是设置环境变量,一行是设置资源加载器,不是我们的主线,所以直接到registerDefaultFilters注册默认的过滤器方法里看一下:
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
在这里我们可以看到第一行代码:
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
往过滤器里添加了一个注解类型的过滤器,并且注解的类型是@Component,我们可以稍微的看一下注释:
/**
* Register the default filter for {@link Component @Component}.
* This will implicitly register all annotations that have the
* {@link Component @Component} meta-annotation including the
* {@link Repository @Repository}, {@link Service @Service}, and
* {@link Controller @Controller} stereotype annotations.
*
Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
* JSR-330's {@link javax.inject.Named} annotations, if available.
*
*/
注册默认的过滤器,如@Component,@Repository,@Service,@Controller,在JavaEE 6版本以后加了@ManagedBean和JSR-330规范的@javax.inject.Named注解等
后面两个可以不用管,最重要的就是前面的四个,因为@Controller,@Service,@Repository注解上包含了@Component注解,所以这些注解都是可以被容器扫描到的,程序走完下面的两个try catch也就结束了。这一步的操作,主要就是向容器中添加注解类型的扫描器,所以该步骤也可以称为指定类路径下的Bean扫描策略。
2.走完上面的两个步骤,this()构造方法也就走完了,我们接着看register(annotatedClasses);方法的执行:
public void register(Class>... annotatedClasses) {
for (Class> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
一直走到这里,我们可以看到,它循环遍历了我们传入的配置类,也就是我们自定义的标注有@Configuration注解的配置类,可以有多个,我们进入registerBean(annotatedClass);方法里,最终走到这里:
public void registerBean(Class> annotatedClass, String name, Class extends Annotation>... qualifiers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
这个方法,看似也没多少东西,开始是根据我们传入的配置类创建一个注解的Bean定义信息,然后获取该Bean定义信息的元数据信息,也就是方法和属性相关的成员,接着调用该方法:
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
对配置类中的元注解进行一系列的操作,例如懒加载,如果包含懒加载的注解,就将该配置类设置为懒加载的,接着判断是否包含这些注解,但是我们可以看到前面qualifiers参数默认传递的是null,所以这里可以暂时可以认为是不会走到if里面的,然后看方法名可以发现最关键的一个就是最下面的一个方法的调用:
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
将上面创建的Bean定义信息注册到传递进来的AnnotationConfigApplicationContext中,也就是IOC容器中,此时这一步也就结束了。这一步简单的概括就是将我们自定义的配置类的Bean定义信息注册到IOC容器中。
3、接着我们看refresh();方法:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
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();
}
}
}
我们可以看到这个方法里调用了很多的方法,并且每个方法再往下都会涉及到IOC容器的各种功能,我们可以一个方法一个方法的进行追踪,但是这里我们就不再往下追踪了,这个方法执行完成后IOC容器也就启动成功了。往后再继续发表其他的博客进行每个方法的解析,一个博客少点内容可以方便博客的阅读,这里的步骤也可以简单的理解为容器的心脏或者核心方法,因为就是这个方法带动了整个IOC的的运转。
4、总结:
IOC容器的启动过程:
1、将容器内部的后置处理器的Bean定义信息给注册到IOC容器中
2、向容器中添加注解类型的扫描器,指定类路径下的Bean扫描策略
3、将我们自定义的配置类的Bean定义信息注册到IOC容器中
4、执行容器的核心方法refresh(),带动Spring的运转
可以看到前三步都是在为第四步做前置的准备,真正的启动IOC容器的还是refresh方法,包括SpringBoot 也是采用这个方法来带动的