spring源码分析之IOC初始化

什么是IOC?

IOC, 即控制反转(Inversion of Control), 它的主要作用是用来解耦。 举个例子来说: 古代的皇帝再临幸妃子的时候, 他不会自己去找妃子, 而是告诉太监, 今天要哪个妃子, 然后太监去将皇帝指定的妃子抬到皇帝的住处, 这个过程就是控制反转。 对应我们的程序来说, 皇帝就是调用类, 妃子就是被调用对象, 而太监就是我们要讲到的IOC容器。

spring源码分析之IOC初始化_第1张图片


导入spring源码

v3.2.12.RELEASE下载地址: http://pan.baidu.com/s/1bngzhUn
v4.1.5.RELEASE下载地址:http://pan.baidu.com/s/1kTnAxqn
spring-tool-suite-3.6.4.RELEASE-e4.4.2-win32-x86_64下载地址: http://pan.baidu.com/s/1bnvsnqZ

本文使用spring3.2, 下载解压后的目录如:

spring源码分析之IOC初始化_第2张图片

执行import-into-eclipse.bat, 根据提示一步一步走完, 这个时候需要下载一些东西, 需要等待一会, 执行完成后目录结构如下:

spring源码分析之IOC初始化_第3张图片


打开spring-tool-suite, 按照import-into-eclipse中的提示导入程序。

准备测试工程

新建一个java工程, 完成后在buildpath中做如下设置:

spring源码分析之IOC初始化_第4张图片

图中各类代码如下:

public class Start {

	public static void main(String[] args) {
		@SuppressWarnings("resource")
		AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext("org.spring");
		System.out.println(appContext.getBean("userDao"));
		System.out.println(new UserService().load().getUsername());
		System.out.println("end");
	}
	
}
public class UserService {
	
	@Autowired
	private UserDao userDao;
	
	public User load() {
		User user = userDao.load();
		return user;
	}

}
@Component
public class UserDao {

	public User load() {
		User user = new User("zhangsan", 11);
		return user;
	}
	
}
public class User {

	private String username;
	
	private Integer age;
	
	public User(String username, Integer age) {
		super();
		this.username = username;
		this.age = age;
	}
……getter、setter省略
}

IOC初始化过程


启动程序, 进入AnnotationConfigApplicationContext类, 我们发现这个类继承了GenericApplicationContext, 间接继承了AbstractApplicationContext。而AbstractApplicationContext则实现了ApplicationContext接口, ApplicationContext接口最终继承了BeanFactory接口。这些继承关系用类图表示如下:

spring源码分析之IOC初始化_第5张图片

这里我们先介绍几个spring中的基础接口:

BeanFactory  Bean抽象工厂的最顶层抽象接口, 所有BeanFactory、ApplicationContext都实现了这个接口

FactoryBean  工厂类的顶层抽象接口, 所有的Factory实例都实现了它

BeanDefinition  Bean定义类, 熟悉spring的同学都知道spring配置文件里面我们会定义很多bean, 那些bean最终在spring程序中的体现就是BeanDefinition了

不过需要注意BeanDefinition并不是bean实例, 它只是bean的定义信息, 包括className、scope、parent、ref等等信息, 真正注入的时候会从缓存或具体的工厂方法获取或生成实例对象。

好了, 回到AnnotationConfigApplicationContext这个类的构造方法:

public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        scan(basePackages);
        refresh();
    }
这里定义了一个reader、一个scanner, 这两个实际上只会使用一个, 具体使用哪个是根据我们传入的参数决定的, 例如在我们的例子中传入的是一个包名, 那么实际调用的就是scanner。


从这里, 我们可以很明显的看出scan方法完成的工作, 即扫描给定包下的所有类, 实际上我们跟踪代码后发现确实如此。

一步一步跟踪进去, 发现最终执行扫描过程的是ClassPathBeanDefinitionScanner类的doScan方法:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
		for (String basePackage : basePackages) {
			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;
	}

beanDefinitions这个集合类实例存的就是扫描出的bean定义

findCandidateComponents(basePackage)  这个方法就是扫描出所有的bean定义

循环体中checkCandidate方法调用之前的部分一直在为bean定义填充信息, 只有在checkCandidate验证通过后, 才会真正调用注册方法registerBeanDefinition(definitionHolder, this.registry);

我们看到这里传入的第二个参数是this.registry, 那么这个参数到底是什么呢?

我们看AnnotationConfigApplicationContext的构造方法中this.scanner = new ClassPathBeanDefinitionScanner(this)这条语句, 可以发现registry就是从这里传入的一个BeanDefinitionRegistry对象, 我们发现他的父类GenericApplicationContext实现了BeanDefinitionRegistry接口, 并且它有一个私有的DefaultListableBeanFactory对象变量, 可见构造方法中的this确实是AnnotationConfigApplicationContext对象本身。

一路跟踪后, 我们发现代码最终到DefaultListableBeanFactory

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition oldBeanDefinition;

		synchronized (this.beanDefinitionMap) {
			oldBeanDefinition = this.beanDefinitionMap.get(beanName);
			if (oldBeanDefinition != null) {
				if (!this.allowBeanDefinitionOverriding) {
					throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
							"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
							"': There is already [" + oldBeanDefinition + "] bound.");
				}
				else {
					if (this.logger.isInfoEnabled()) {
						this.logger.info("Overriding bean definition for bean '" + beanName +
								"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
					}
				}
			}
			else {
				this.beanDefinitionNames.add(beanName);
				this.frozenBeanDefinitionNames = null;
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}
beanDefinitionMap 这个变量的定义为
/** Map of bean definition objects, keyed by bean name */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
他就是真正的Bean定义类存放的地方。 并且在注册bean定义的时候还会根据allowBeanDefinitionOverriding这个属性的值来判断是否允许覆盖同名bean, 但是在3.2中这个属性默认是无法设值得, 如果我们要改动他的值, 只能通过继承, 添加set方法来实现。

到这里IOC容器加载Bean定义的过程就结束了, 接下来我会再起一篇博文, 详细介绍IOC的注入过程, 包括单例对象、懒加载等的处理过程。




你可能感兴趣的:(spring源码分析之IOC初始化)