一、ApplicationContext接口设计
ApplicationContext是spring中较高级的容器。和BeanFactory类似,它可以加载配置文件中定义的bean,当有请求的时候分配bean。 另外,它增加了企业所需要的功能,比如,从属性文件解析文本信息和将事件传递给所指定的监听器。接口设计图如下:
,
ApplicationContext继承5个接口:
1.2个核心接口:
ListableBeanFactory:支持获取bean 工厂的所有bean实例
HierarchicalBeanFactory:支持继承关系
2.3个拓展接口:
MessageSource:提供国际化支持
ApplicationEventPublisher:支持事件驱动模型中的事件发布器,这些事件和Bean的生命周期的结合为Bean的管理提供了便利。
ResourcePatternResolver:资源解析器
常见实现类:
1.FileSystemXmlApplicationContext:从指定文件地址的加载xml定义的bean
2.ClassPathXmlApplicationContext:从类路径下载入xml定义的bean
3.XmlWebApplicationContext:web 应用程序的范围内载入xml定义的bean
二、深入源码,看IOC容器初始化
为了方便理解和追踪代码,使用常用实现类ClassPathXmlApplicationContext写了一个小例子,步骤如下:
1).在类路径下新建xml,定义一个bean,其中daoImpl就是bean的名字,spring.aop.xml.dao.impl.DaoImpl对应具体的一个pojo.
1 <bean id="daoImpl" class="spring.aop.xml.dao.impl.DaoImpl" />
2).main方法中直接载入xml,然后获取bean,最后执行bean实例的方法。
1 public static void main(String[] args) {
2 //源码入口,从类路径下读取xml
3 ApplicationContext ac1 = new ClassPathXmlApplicationContext("aop.xml");
4 Dao dao = (Dao)ac1.getBean("daoImpl");//根据名称获取Bean
5 dao.select();//执行Bean实例方法
}
下面我们就分析ClassPathXmlApplicationContext源码,来看看都做了什么。
2.1ClassPathXmlApplicationContext类图
DefaultResourceLoader,该类设置classLoader,并且将配置文件 封装为Resource文件。
AbstractApplicationContext,该类完成了大部分的IOC容器初始化工作,同时也提供了扩展接口留给子类去重载。该类的refresh()函数是核心初始化操作。
AbstractRefreshableApplicationContext,该类支持刷新BeanFactory。
AbstractRefreshableConfigApplicationContext,该类保存了配置文件路径
AbstractXmlApplicationContext:该类支持解析bean定义文件
最后ClassPathXmlApplicationContext:只提供了一个简单的构造函数
Spring 将类职责分开,形成职责链,每一层次的扩展 都只是添加了某个功能
然后父类定义大量的模板,让子类实现,父类层层传递到子类 直到某个子类重载了抽象方法。这里应用到了职责链设计模式和模板设计模式,IOC是个容器工厂设计模式。
2.2 回顾上面的小例子,new ClassPathXmlApplicationContext("aop.xml");这行代码做了什么?
1 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
2 throws BeansException {
3
4 super(parent);//把ApplicationContext作为父容器,上述测试类中由于直接载入的xml,没有父容器所以实际传了null
5 setConfigLocations(configLocations);//替换${}后设置配置路径
6 if (refresh) {
7 refresh();//核心方法
8 }
9 }
ClassPathXmlApplicationContext的refresh()实际上就是调用了AbstractApplicationContext的refresh()方法。全方法被synchronized同步块锁住,源码如下:
1 public void refresh() throws BeansException, IllegalStateException {
2 synchronized (this.startupShutdownMonitor) {
3 //准备刷新的上下文环境,例如对系统属性或者环境变量进行准备及验证。
4 prepareRefresh();
5
6 //启动子类的refreshBeanFactory方法.解析xml
7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
8
9 //为BeanFactory配置容器特性,例如类加载器、事件处理器等.
10 prepareBeanFactory(beanFactory);
11
12 try {
13 //设置BeanFactory的后置处理. 空方法,留给子类拓展用。
14 postProcessBeanFactory(beanFactory);
15
16 //调用BeanFactory的后处理器, 这些后处理器是在Bean定义中向容器注册的.
17 invokeBeanFactoryPostProcessors(beanFactory);
18
19 //注册Bean的后处理器, 在Bean创建过程中调用.
20 registerBeanPostProcessors(beanFactory);
21
22 //初始化上下文中的消息源,即不同语言的消息体进行国际化处理
23 initMessageSource();
24
25 //初始化ApplicationEventMulticaster bean,应用事件广播器
26 initApplicationEventMulticaster();
27
28 //初始化其它特殊的Bean, 空方法,留给子类拓展用。
29 onRefresh();
30
31 //检查并向容器注册监听器Bean
32 registerListeners();
33
34 //实例化所有剩余的(non-lazy-init) 单例Bean.
35 finishBeanFactoryInitialization(beanFactory);
36
37 //发布容器事件, 结束refresh过程.
38 finishRefresh();
39 }
40
41 catch (BeansException ex) {
42 if (logger.isWarnEnabled()) {
43 logger.warn("Exception encountered during context initialization - " +
44 "cancelling refresh attempt: " + ex);
45 }
46
47 //销毁已经创建的单例Bean, 以避免资源占用.
48 destroyBeans();
49
50 //取消refresh操作, 重置active标志.
51 cancelRefresh(ex);
52
53 // Propagate exception to caller.
54 throw ex;
55 }
56
57 finally {
58 //重置Spring的核心缓存
60 resetCommonCaches();
61 }
62 }
63 }
2.3 Resources定位
refresh方法中obtainFreshBeanFactory方法调用了refreshBeanFactory,该方法使用DefaultListableBeanFactory去定位resources资源
1 protected final void refreshBeanFactory() throws BeansException {
2 if (hasBeanFactory()) {
3 destroyBeans();
4 closeBeanFactory();
5 }
6 try {//创建并设置DefaultListableBeanFactory同时调用loadBeanDefinitions载入loadBeanDefinition
7 DefaultListableBeanFactory beanFactory = createBeanFactory();
8 beanFactory.setSerializationId(getId());
9 customizeBeanFactory(beanFactory);
10 loadBeanDefinitions(beanFactory);//核心方法
11 synchronized (this.beanFactoryMonitor) {
12 this.beanFactory = beanFactory;
13 }
14 }
15 catch (IOException ex) {
16 throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
17 }
18 }
loadBeanDefinitions其具体实现在AbstractXmlApplicationContext中,定义了一个Reader作为入参执行载入过程:
1 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
2 // 为给定的bean工厂创建一个reader
3 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
4
5 // Configure the bean definition reader with this context's
6 // resource loading environment.
7 beanDefinitionReader.setEnvironment(this.getEnvironment());
8 beanDefinitionReader.setResourceLoader(this);
9 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
10
11 // Allow a subclass to provide custom initialization of the reader,
12 // then proceed with actually loading the bean definitions.
13 initBeanDefinitionReader(beanDefinitionReader);
14 loadBeanDefinitions(beanDefinitionReader);//核心方法
15 }
loadBeanDefinitions方法如下:
1 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
2 Resource[] configResources = getConfigResources();
3 if (configResources != null) {
4 reader.loadBeanDefinitions(configResources);
5 }
6 String[] configLocations = getConfigLocations();
7 if (configLocations != null) {
8 reader.loadBeanDefinitions(configLocations);
9 }
10 }
getConfigResources采用模板方法设计模式,具体的实现由子类完成,实际上这里getConfigResources调用的就是子类ClassPathXmlApplicationContext的getConfigResources方法。ClassPathXmlApplicationContext继承了DefaultResourceLoader,具备了Resource加载资源的功能。至此完成了Resource定位!
2.4 BeanDefinition载入
这里支持2种模式:1.模板匹配多资源,生成Resource[]。2.载入单个资源url绝对地址,生成一个Resource
1 public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
2 ResourceLoader resourceLoader = getResourceLoader();//获取ResourceLoader资源加载器
3 if (resourceLoader == null) {
4 throw new BeanDefinitionStoreException(
5 "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
6 }
7 // 1.匹配模板解析 ClassPathXmlApplicationContext是ResourcePatternResolver接口的实例
8 if (resourceLoader instanceof ResourcePatternResolver) {
9
10 try {//接口ResourcePatternResolver
11 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
12 int loadCount = loadBeanDefinitions(resources);
13 if (actualResources != null) {
14 for (Resource resource : resources) {
15 actualResources.add(resource);
16 }
17 }
18 if (logger.isDebugEnabled()) {
19 logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
20 }
21 return loadCount;
22 }
23 catch (IOException ex) {
24 throw new BeanDefinitionStoreException(
25 "Could not resolve bean definition resource pattern [" + location + "]", ex);
26 }
27 }
28 else {
29 // 2.载入单个资源url绝对地址
30 Resource resource = resourceLoader.getResource(location);
31 int loadCount = loadBeanDefinitions(resource);
32 if (actualResources != null) {
33 actualResources.add(resource);
34 }
35 if (logger.isDebugEnabled()) {
36 logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
37 }
38 return loadCount;
39 }
40 }
loadBeanDefinitions最终调用XmlBeanDefinitionReader.doLoadBeanDefinitions(),如下:
1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
2 throws BeanDefinitionStoreException {
3 try {// 取得xml文件的Document,解析过程是由DocumentLoader完成,默认为DefaultDocumentLoader
4 Document doc = doLoadDocument(inputSource, resource);
5 return registerBeanDefinitions(doc, resource);// 启动对BeanDefinition的详细解析过程,这个解析会使用到spring的BEAN配置规则
6 }
7 catch (BeanDefinitionStoreException ex) {
8 throw ex;
9 }
10 catch (SAXParseException ex) {
11 throw new XmlBeanDefinitionStoreException(resource.getDescription(),
12 "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
13 }
14 catch (SAXException ex) {
15 throw new XmlBeanDefinitionStoreException(resource.getDescription(),
16 "XML document from " + resource + " is invalid", ex);
17 }
18 catch (ParserConfigurationException ex) {
19 throw new BeanDefinitionStoreException(resource.getDescription(),
20 "Parser configuration exception parsing XML from " + resource, ex);
21 }
22 catch (IOException ex) {
23 throw new BeanDefinitionStoreException(resource.getDescription(),
24 "IOException parsing XML document from " + resource, ex);
25 }
26 catch (Throwable ex) {
27 throw new BeanDefinitionStoreException(resource.getDescription(),
28 "Unexpected exception parsing XML document from " + resource, ex);
29 }
30 }
registerBeanDefinitions是按照spring的bean配置规则解析,源码如下:
1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
2 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
3 int countBefore = getRegistry().getBeanDefinitionCount();
4 documentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 核心方法
5 return getRegistry().getBeanDefinitionCount() - countBefore;
6 }
至此就完成了BeanDefinition的载入,BeanDefinition的载入分为两个部分,
1.调用xml解析器得到的document对象,但是这个对象并没有按照spring的bean规则进行解析。
2.DefaultBeanDefinitionDocumentReader的registerBeanDefinitions按照Spring的Bean规则进行解析。
2.5 BeanDefinition解析和注册
registerBeanDefinitions方法调用了doRegisterBeanDefinitions
1 protected void doRegisterBeanDefinitions(Element root) {
2 // Any nested <beans> elements will cause recursion in this method. In
3 // order to propagate and preserve <beans> default-* attributes correctly,
4 // keep track of the current (parent) delegate, which may be null. Create
5 // the new (child) delegate with a reference to the parent for fallback purposes,
6 // then ultimately reset this.delegate back to its original (parent) reference.
7 // this behavior emulates a stack of delegates without actually necessitating one.
8 BeanDefinitionParserDelegate parent = this.delegate;
9 this.delegate = createDelegate(getReaderContext(), root, parent);
10
11 if (this.delegate.isDefaultNamespace(root)) {
12 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
13 if (StringUtils.hasText(profileSpec)) {
14 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
15 profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
16 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
17 if (logger.isInfoEnabled()) {
18 logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
19 "] not matching: " + getReaderContext().getResource());
20 }
21 return;
22 }
23 }
24 }
25
26 preProcessXml(root);
27 parseBeanDefinitions(root, this.delegate);// 从Document的根元素开始进行Bean定义的Document对象
28 postProcessXml(root);
29
30 this.delegate = parent;
31 }
1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
2 if (delegate.isDefaultNamespace(root)) {
3 NodeList nl = root.getChildNodes();
4 for (int i = 0; i < nl.getLength(); i++) {
5 Node node = nl.item(i);
6 if (node instanceof Element) {
7 Element ele = (Element) node;
8 if (delegate.isDefaultNamespace(ele)) {
9 parseDefaultElement(ele, delegate);
10 }
11 else {
12 delegate.parseCustomElement(ele);
13 }
14 }
15 }
16 }
17 else {
18 delegate.parseCustomElement(root);
19 }
20 }
21
22 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
23 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
24 importBeanDefinitionResource(ele);
25 }
26 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
27 processAliasRegistration(ele);
28 }
29 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
30 processBeanDefinition(ele, delegate);
31 }
32 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
33 // recurse
34 doRegisterBeanDefinitions(ele);
35 }
36 }
processBeanDefinition就是对bean标签的解析和注册
1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
2 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);// 1.解析
3 if (bdHolder != null) {
4 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);//代理去装饰:典型的装饰器模式
5 try {
6 // 2.向IOC容器注册Bean定义+bean工厂
7 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
8 }
9 catch (BeanDefinitionStoreException ex) {
10 getReaderContext().error("Failed to register bean definition with name '" +
11 bdHolder.getBeanName() + "'", ele, ex);
12 }
13 // 3.触发注册事件: spring只提供了EmptyReaderEventListener空实现,如果需要你可以自定义
14 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
15 }
16 }
解析:parseBeanDefinitionElement方法就是具体的解析入口。解析elemnent->BeanDefinitionHolder,追踪parseBeanDefinitionElement:
1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
2 String id = ele.getAttribute(ID_ATTRIBUTE);// 获取id
3 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);// 获取name
4
5 List<String> aliases = new ArrayList<String>();// 获取别名
6 if (StringUtils.hasLength(nameAttr)) {
7 String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
8 aliases.addAll(Arrays.asList(nameArr));
9 }
10
11 String beanName = id;
12 if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
13 beanName = aliases.remove(0);
14 if (logger.isDebugEnabled()) {
15 logger.debug("No XML 'id' specified - using '" + beanName +
16 "' as bean name and " + aliases + " as aliases");
17 }
18 }
19
20 if (containingBean == null) {
21 checkNameUniqueness(beanName, aliases, ele);
22 }
23
24 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
25 if (beanDefinition != null) {
26 if (!StringUtils.hasText(beanName)) {
27 try {
28 if (containingBean != null) {
29 beanName = BeanDefinitionReaderUtils.generateBeanName(
30 beanDefinition, this.readerContext.getRegistry(), true);
31 }
32 else {
33 beanName = this.readerContext.generateBeanName(beanDefinition);
34 // Register an alias for the plain bean class name, if still possible,
35 // if the generator returned the class name plus a suffix.
36 // This is expected for Spring 1.2/2.0 backwards compatibility.
37 String beanClassName = beanDefinition.getBeanClassName();
38 if (beanClassName != null &&
39 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
40 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
41 aliases.add(beanClassName);
42 }
43 }
44 if (logger.isDebugEnabled()) {
45 logger.debug("Neither XML 'id' nor 'name' specified - " +
46 "using generated bean name [" + beanName + "]");
47 }
48 }
49 catch (Exception ex) {
50 error(ex.getMessage(), ele);
51 return null;
52 }
53 }
54 String[] aliasesArray = StringUtils.toStringArray(aliases);
55 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
56 }
57
58 return null;
59 }
好吧,parseBeanDefinitionElement才是核心方法,追踪:
1 public AbstractBeanDefinition parseBeanDefinitionElement(
2 Element ele, String beanName, BeanDefinition containingBean) {
3
4 this.parseState.push(new BeanEntry(beanName));
5
6 String className = null;
7 if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
8 className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
9 }
10
11 try {
12 String parent = null;
13 if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
14 parent = ele.getAttribute(PARENT_ATTRIBUTE);
15 }// 这里生成需要的BeanDefinition对象,为Bean定义信息的载入做准备
16 AbstractBeanDefinition bd = createBeanDefinition(className, parent);
17 // 1.解析<bean>元素属性
18 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
19 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));//2.解析description
20 //对各种BEAN元素信息进行解析
21 parseMetaElements(ele, bd);// 3.解析<meta>子元素
22 parseLookupOverrideSubElements(ele, bd.getMethodOverrides());//4.解析<lookup-method>子元素
23 parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//5.解析<replaced-method>子元素
24
25 parseConstructorArgElements(ele, bd);//6.解析<constructor-arg>
26 parsePropertyElements(ele, bd);//7.解析<property>
27 parseQualifierElements(ele, bd);//8.解析<qualifier>
28
29 bd.setResource(this.readerContext.getResource());
30 bd.setSource(extractSource(ele));
31
32 return bd;
33 }
34 catch (ClassNotFoundException ex) {
35 error("Bean class [" + className + "] not found", ele, ex);
36 }
37 catch (NoClassDefFoundError err) {
38 error("Class that bean class [" + className + "] depends on not found", ele, err);
39 }
40 catch (Throwable ex) {
41 error("Unexpected failure during bean definition parsing", ele, ex);
42 }
43 finally {
44 this.parseState.pop();
45 }
46
47 return null;
48 }
经过这样逐层的分析,我们在xml文件中定义的BeanDefinition就被整个载入到IOC容器中,并在容器中建立了数据映射。这些数据结构可以以AbstractBeanDefinition为入口让IOC容器执行索引,查询和操作。
注册:registerBeanDefinition方法就是具体的注册入口。追踪registerBeanDefinition:
1 public static void registerBeanDefinition(
2 BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
3 throws BeanDefinitionStoreException {
4
5 // Register bean definition under primary name.
6 String beanName = definitionHolder.getBeanName();
7 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());//向IoC容器注册BeanDefinition
8
9 // 如果解析的BeanDefinition有别名, 向容器为其注册别名.
10 String[] aliases = definitionHolder.getAliases();
11 if (aliases != null) {
12 for (String alias : aliases) {
13 registry.registerAlias(beanName, alias);
14 }
15 }
16 }
registerBeanDefinition具体实现类:DefaultListableBeanFactory.registerBeanDefinition方法
1 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
2 throws BeanDefinitionStoreException {
3
4 Assert.hasText(beanName, "Bean name must not be empty");
5 Assert.notNull(beanDefinition, "BeanDefinition must not be null");
6
7 if (beanDefinition instanceof AbstractBeanDefinition) {
8 try {
9 ((AbstractBeanDefinition) beanDefinition).validate();
10 }
11 catch (BeanDefinitionValidationException ex) {
12 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
13 "Validation of bean definition failed", ex);
14 }
15 }
16
17 BeanDefinition oldBeanDefinition;
18
19 oldBeanDefinition = this.beanDefinitionMap.get(beanName);
20 if (oldBeanDefinition != null) {
21 if (!isAllowBeanDefinitionOverriding()) {
22 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
23 "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
24 "': There is already [" + oldBeanDefinition + "] bound.");
25 }
26 else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
27 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
28 if (this.logger.isWarnEnabled()) {
29 this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
30 "' with a framework-generated bean definition: replacing [" +
31 oldBeanDefinition + "] with [" + beanDefinition + "]");
32 }
33 }
34 else if (!beanDefinition.equals(oldBeanDefinition)) {
35 if (this.logger.isInfoEnabled()) {
36 this.logger.info("Overriding bean definition for bean '" + beanName +
37 "' with a different definition: replacing [" + oldBeanDefinition +
38 "] with [" + beanDefinition + "]");
39 }
40 }
41 else {
42 if (this.logger.isDebugEnabled()) {
43 this.logger.debug("Overriding bean definition for bean '" + beanName +
44 "' with an equivalent definition: replacing [" + oldBeanDefinition +
45 "] with [" + beanDefinition + "]");
46 }
47 }
48 this.beanDefinitionMap.put(beanName, beanDefinition);
49 }
50 else {
51 if (hasBeanCreationStarted()) {
52 // Cannot modify startup-time collection elements anymore (for stable iteration)
53 synchronized (this.beanDefinitionMap) {
54 this.beanDefinitionMap.put(beanName, beanDefinition);
55 List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
56 updatedDefinitions.addAll(this.beanDefinitionNames);
57 updatedDefinitions.add(beanName);
58 this.beanDefinitionNames = updatedDefinitions;
59 if (this.manualSingletonNames.contains(beanName)) {
60 Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
61 updatedSingletons.remove(beanName);
62 this.manualSingletonNames = updatedSingletons;
63 }
64 }
65 }
66 else {
67 // Still in startup registration phase
68 this.beanDefinitionMap.put(beanName, beanDefinition);
69 this.beanDefinitionNames.add(beanName);
70 this.manualSingletonNames.remove(beanName);
71 }
72 this.frozenBeanDefinitionNames = null;
73 }
74
75 if (oldBeanDefinition != null || containsSingleton(beanName)) {
76 resetBeanDefinition(beanName);
77 }
78 }
完成了BeanDefinition的注册,就完成了IOC容器的初始化过程。容器的作用就是对这些信息进行处理和维护,这些信息就是容器建立依赖反转的基础。
三、总结
本文先介绍ApplicationContext接口设计,再从其一个最常见实现类ClassPathXmlApplicationContext写了一个小例子,作为源码追踪的入口。
追踪了主要包括Resourse定位、BeanDefinition的载入、解析和注册3个模块。至此,容器初始化(Bean已生成)已完成,下一章我们看依赖注入的源码。