前期准备

首先搭建一个简单的Spring Demo工程

项目目录结构如下图所示:

applicationContect.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="chinese" class="com.bean.ChineseImpl">
<property name="name">
<value>小明</value>
</property>
<property name="age">
<value>10</value>
</property>
</bean>
<bean id="american" class="com.bean.AmericanImpl">
<property name="name">
<value>Tom</value>
</property>
<property name="age">
<value>15</value>
</property>
</bean>
</beans>

Person.java

package com.bean;

public interface Person{

    public void Speak();
}

ChineseImpl.java

package com.bean;

public class ChineseImpl implements Person{
private String name;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public void Speak() {
// TODO Auto-generated method stub
System.out.println("I'm Chinese,My name is "+this.name+",I'm "+this.age+" years old!");
}
}

AmericanImpl.java

package com.bean;

public class AmericanImpl implements Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void Speak() {
// TODO Auto-generated method stub
System.out.println("I'm American,My name is "+this.name+",I'm "+this.age+" years old!");
}
}

Test.java

package com.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.bean.Person; public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("chinese");
person.Speak();
person = (Person) context.getBean("american");
person.Speak();
}
}

下面将按照Spring初始化的过程:

构造函数

ClassPathXmlApplicationContext构造函数(ClassPathXmlApplicationContext[只能读放在web-info/classes目录下的配置文件],FileSystemXmlApplicationContext读具体路径)

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}

根据传入参数的不同,调用不同的构造函数,最终调用以下构造函数

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

设置配置文件路径

即AbstractRefreshableConfigApplicationContext.setConfigLocations

    public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}

resolvePath:

    protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}

此方法的目的在于将占位符(placeholder)解析成实际的地址。比如可以这么写: new ClassPathXmlApplicationContext("classpath:config.xml");那么classpath:就是需要被解析的

refesh()

Spring bean解析就在此方法,所以单独提出来。

AbstractApplicationContext.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) {
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;
}
}
}

prepareRefresh

    protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.active.set(true); if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
} // Initialize any placeholder property sources in the context environment
initPropertySources(); // Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
}

属性校验

AbstractEnvironment.validateRequiredProperties:

    @Override
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
this.propertyResolver.validateRequiredProperties();
}

AbstractPropertyResolver.validateRequiredProperties:

    @Override
public void validateRequiredProperties() {
MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
for (String key : this.requiredProperties) {
if (this.getProperty(key) == null) {
ex.addMissingRequiredProperty(key);
}
}
if (!ex.getMissingRequiredProperties().isEmpty()) {
throw ex;
}
}

requiredProperties是通过setRequiredProperties方法设置的,保存在一个list里面,默认是空的,也就是不需要校验任何属性

BeanFactory创建

由 refesh() 中的 obtainFreshBeanFactory 调用 AbstractRefreshableApplicationContext.refreshBeanFactory:

    @Override
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);
}
}

BeanFactory定制

AbstractRefreshableApplicationContext.customizeBeanFactory方法用于给子类提供一个自由配置的机会,默认实现:

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}

Bean加载

AbstractXmlApplicationContext.loadBeanDefinitions,这个便是核心的bean加载了:

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}

最新文章

  1. 文件上传之——用SWF插件实现文件异步上传和头像截取
  2. 千万用户级别应用系统背后的SOA组件化容器
  3. try : finally语句
  4. P2312 解方程
  5. WCF服务中,[DataMember]属性标记的属性一定要有set访问器
  6. curl 报错记录,mark
  7. android sdk manager 闪退 打不开问题
  8. (转载)mysql查询一天,查询一周,查询一个月的数据
  9. java mail 使用 gmail smtp 发送邮件
  10. BootStrap 智能表单系列 六 表单数据绑定(编辑页面的数据绑定)
  11. postcss的安装与使用
  12. xgboost 参数调优指南
  13. [Solution] JZOJ-5806 简单的操作
  14. 协同过滤CF算法之入门
  15. Spring中的IoC(控制反转)具体是什么东西
  16. 【多视图几何】TUM 课程 第4章 同名点匹配
  17. bzoj 4242 水壶 (多源最短路+最小生成树+启发式合并)
  18. [Functional Programming] Build a Linear congruential generator
  19. pl/sql登录时,数据库下拉框没有任何内容
  20. [CF1042D] Petya and Array

热门文章

  1. DB2分页
  2. 《Java语言程序设计》
  3. vue8种通信方式
  4. C/C++编程
  5. Matlab JPEG详细介绍
  6. vue v-slot
  7. 记:linux服务器启动重启WEB项目启动成功,长时间卡住未响应
  8. HTTP报文学习
  9. Python多线程VS多进程
  10. OBB碰撞