以classpathXmlApplication为例

入口方法包含3个部分,

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

1.继承父类,没什么东西

2.设置配置文件

3.执行refresh方法(关键)。下面我们就这两个方法看看内部实现

设置配置文件,这块其实没什么东西,就是给context对象设置一个configLocations的数组,我们看一下context类的继承关系

下面看重点的refresh方法

 public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {//锁住一个对象,防止多线程同时执行初始化的操作
// Prepare this context for refreshing.准备上下文,这里设置一下开始实现,准备propery等
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();
}
}
}

这个代码有点长,我们把每个方法干什么先研究一下,在深入看每个方法怎么实现的。

从7行开始看,这个方法是为了一个refreshBeanFactory。返回的类是ConfigurableListableBeanFactory,而这个factory是一个接口,我们待会看看这个接口有哪些实现,先看看这个方法内部实现

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

我们看到最后return的beanFactory就是ConfigurableListableBeanFactory。而这个接口只有一个default实现类DefaultListableBeanFactory。我们看看这个类主要有哪些成员变量

 private boolean allowEagerClassLoading = true;

     /** Optional OrderComparator for dependency Lists and arrays */
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<Class<?>, Object>(16); /** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256); /** Map of singleton and non-singleton bean names, keyed by dependency type */
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64); /** Map of singleton-only bean names, keyed by dependency type */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64); /** List of bean definition names, in registration order */
private volatile List<String> beanDefinitionNames = new ArrayList<String>(256); /** List of names of manually registered singletons, in registration order */
private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16); /** Cached array of bean definition names in case of frozen configuration */
private volatile String[] frozenBeanDefinitionNames; /** Whether bean definition metadata may be cached for all beans */
private volatile boolean configurationFrozen = false;

这些成员变量有机会我们一个个分析下,我们知道每个bean 有一个beanDefinition对象来定义。在13行,我们看到有一个BeanDefinition的Map,我们随便调试一下,看看这个里面存了什么东西。

这里面竟然只有7个对象,分别是:ConfigurationClassPostProcessor、DefaultEventListenerFactory、MessageResolver、EventListenerMethodProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PropertiesFactoryBean、RequiredAnnotationBeanPostProcessor。这七个对象怎么来的呢,举个例子来看ConfigurationClassPostProcessor,这个类说明是,当配置文件中

Registered by default when using {@code <context:annotation-config/>} or
* {@code <context:component-scan/>}有这两个配置的时候,便会注入这么个类。好吧,那我们看看在哪里register的。我们猜测是在

refreshBeanFactory();这个方法里面。那看看这个方法
 protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

我们看到第7行,创建了一个DefaultListableBeanFactory ,第10行有loadBeanDefinition。应该是在这里处理的。我们还是先调试下看看。执行7行代码,这个时候beanDefinitionMap是空的。执行完10行代码,我们的beanDefinitionMap有值了。这里面为了加深理解,我们在我们的spring-config.xml文件中加一个bean看看会怎么样。原来的spring-config.xml文件如下

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.1.xsd"> <context:annotation-config/> <context:component-scan base-package="com.newbie.common"></context:component-scan> <util:properties id="systemProperties" location="classpath:conf/user.properties" /> </beans>

我们随便加一个bean,如下图所示,有多个一个beanDefinition。所以这个地就是定义所以beanDefinition的入口,而我们从autowire的bean是由相关processor处理的,这个今后如果有时间的话,我们在分析。我们继续往下看

我们回到原来的refresh方法里面。

 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();
}
}
}

我们现在知道第7行返回的这个ConfigurableListableBeanFactory 有我们所有的beanDefintion。这个方法是给ConfigurableListableBeanFactory 设置了若干预设变量,现在我们也不清楚这个变量是干嘛的,我们先跳过这个方法,等回头再分析他。

第14行postProcessBeanFactory(ConfigurableListableBeanFactory )。我们看看这个代码是做什么事情,我们有一个关注点,我们@autowired的bean是怎么被处理的。这个代码,会根据不同context子类加入不同Processors,这个我们也暂时不分析他,等回头再看

第17行invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory )。这个方法应该就是能看到bean是如何创建的。这个代码比较长,我们先把调用关系简单画出来

执行invokeBeanFactoryPostProcessors之后,这里主要是讲各个processors类注册进去,这里需要获得具体的bean了,根据beanName和BeanDefinition。如何获得bean,通过DefaultListableBeanFactory的getBean方法,这里判断bean是单利还是原型的,进入不同的getBean的逻辑,之后调用的AbstractAutowireCapableBeanFactory的createBean方法,之后通过反射来获得对应的bean。注意看一下doCreateBean方法里面的populateBean()方法,这里能够完成对属性的注入。

上面这个方法,我们调用的时候发现就注册了一个ConfigurationClassPostProcessor,也不知道干嘛的。后来通过搜索了解到这个方法主要是用于处理spring的后置处理器的相关内容,参考https://www.cnblogs.com/sishang/p/6588542.html和https://www.cnblogs.com/sishang/p/6576665.html。

 

spring bean 加载过程(spring)的更多相关文章

  1. Spring bean加载2--FactoryBean情况处理

    Spring bean加载2--FactoryBean情况处理 在Spring bean加载过程中,每次bean实例在返回前都会调用getObjectForBeanInstance来处理Factory ...

  2. 工厂模式模拟Spring的bean加载过程

    一.前言    在日常的开发过程,经常使用或碰到的设计模式有代理.工厂.单例.反射模式等等.下面就对工厂模式模拟spring的bean加载过程进行解析,如果对工厂模式不熟悉的,具体可以先去学习一下工厂 ...

  3. Spring IOC bean加载过程

    首先我们不要在学习Spring的开始产生畏难情绪.Spring没有臆想的那么高深,相反,它帮我们再项目开发中制定项目框架,简化项目开发.它的主要功能是将项目开发中繁琐的过程流程化,模式化,使用户仅在固 ...

  4. 07.Spring Bean 加载 - BeanDefinitionReader

    基本概念 BeanDefinitionReader ,该接口的作用就是加载 Bean. 在 Spring 中,Bean 一般来说都在配置文件中定义.而在配置的路径由在 web.xml 中定义.所以加载 ...

  5. SSH 之 Spring的源码(一)——Bean加载过程

    看看Spring的源码,看看巨人的底层实现,拓展思路,为了更好的理解原理,看看源码,深入浅出吧.本文基于Spring 4.0.8版本. 首先Web项目使用Spring是通过在web.xml里面配置 o ...

  6. 看看Spring的源码(一)——Bean加载过程

    首先Web项目使用Spring是通过在web.xml里面配置org.springframework.web.context.ContextLoaderListener初始化IOC容器的. <li ...

  7. spring bean加载顺序指定方式之一

    在某些情况下,我们在容器启动的时候做一些事情,举个例子,加载缓存等.. 此时我们会希望某个bean先被加载并执行其中的afterpropertiesset方法. 因为spring默认是通过contex ...

  8. Spring bean加载之1:BeanFactory和FactoryBean

    BeanFactory BeanFactory:以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂.在Spring中,BeanFactory是IOC容器的核心接口,它的职责包 ...

  9. Spring bean加载多个配置文件

    除了写很简单的加载一个xml,加载多个的情况一直没用到,在公司里也不会由自己处理这个问题,现在需要用到了,就研究验证一下. 使用的案例还是上面的例子. 只有,将原来的beans.xml分成两个部分. ...

随机推荐

  1. 今天犯了个小错误:_dataArray.count>1 和_dataArray.count>0搞混淆了

    _dataArray.count>1 和_dataArray.count>0搞混淆了:当数据为一条时,条件不成立.应该_dataArray.count>=1  或者>0   ( ...

  2. Linux初接触随笔02

    刚开始把Linux既拿来用,又拿来学习怎么用,感觉真不顺手,手上应该有一本实体书籍,专门拿来学习用会好点,但是我现在手头没有,又把系统作为日常使用,只能说太不友好了,坚持不住了,以后等需要用的时候再弄 ...

  3. Redmine迁移至华为软件开发云-项目管理

    一.方案概述 要想将Redmine中某个项目的数据导入到华为软件开发云(以下简称开发云),如果说是按照Redmine中的数据一条一条的在开发云中新建出来,肯定不是一个明智的方案,下面就是给大家介绍一个 ...

  4. vue 百度地图

    <template lang="pug"> #select-area-in-map-content #show-message-info el-popover(plac ...

  5. 使用Visual Studio 2010 一步一步创建Powershell Module 和 Cmdlet

    现在就用C#写一个超级简单的Module和Cmdlet 1. 在VS中创建一个Library的项目 文件->新建->项目->C#->Class Library 在这里给我们的C ...

  6. .net命名空间和程序集详解

    命名空间是一种用于将逻辑上相似的类按层次结构分组的机制.这种机制防止了命名冲突.在这种结构化采用被点号"."分隔的单词来实现.通常最顶层的命名空间是System,例如System; ...

  7. override 与overload 的差别

    方法的重写(Overriding)和重载(Overloading)是Java多态性的不同表现.   重写(Overriding)是父类与子类之间多态性的一种表现,而重载(Overloading)是一个 ...

  8. 解决Eclipse代码提示消失的方法

    注意:首先要做的是windows->preferences->java->Editor->"ContentAssist", auto-activetion中 ...

  9. modern-cpp-features

    C++17/14/11 Overview Many of these descriptions and examples come from various resources (see Acknow ...

  10. SEED缓冲区溢出实验笔记——Return_to_libc

    参考:http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Return_to_libc/    http://drops.wooyun.org/ ...