1、IOC简介
IOC(Inversion of Control):即”控制反转”,也叫DI(Dependency Injection):DI即依赖注入。
所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。
IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等。
对象和对象关系怎么表示?
可以用 xml , properties 文件等语义化配置文件表示。
描述对象关系的文件存放在哪里?
可能是 classpath , filesystem ,或者是 URL 网络资源, servletContext 等。
2、Spring IOC的简单实现
2.1、创建实体类User
package com.vesus.spring.model;
/**
* @Description:
* @Author: vesus
* @CreateDate: 2018/5/31 下午11:44
* @Version: 1.0
*/
public class User {
private String id ;
private String name ;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.2、创建applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.vesus.spring.model.User" />
</beans>
2.3、新建测试类
package com.vesus.spring.model.test;
import com.vesus.spring.model.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description:
* @Author: vesus
* @CreateDate: 2018/5/31 下午11:48
* @Version: 1.0
*/
public class Test {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) beanFactory.getBean("user") ;
System.err.println(user.getDesc());
}
}
3、源码分析
3.1、入口类
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);//设置配置文件位置
if (refresh) {
refresh();//主要的加载bean的过程
}
}
有源码可以看到最主要的方法集中在refresh()上,下面分析一下refresh的源码。
3.2、refresh()源码分析
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新上下文环境
prepareRefresh();
//读取xml文件的,初始化beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备beanfactory来使用这个上下文.做一些准备工作,例如classloader,beanfactoryPostProcessor等
prepareBeanFactory(beanFactory);
try {
//空方法,供子类使用
postProcessBeanFactory(beanFactory);
//开始执行注册到该上下文的BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);
//开始注册BeanPostProcessor来拦截其他的bean的初始化过程
registerBeanPostProcessors(beanFactory);
//初始化消息源
initMessageSource();
//注册上下文事件的广播集
initApplicationEventMulticaster();
//初始化其他上下文中子类中的特殊bean
onRefresh();
//注册监听器
registerListeners();
//初始化单例
finishBeanFactoryInitialization(beanFactory);
//初始化完成
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();
}
}
}
Refresh 首先进行上下本刷新,然后读取xml文件,并初始化beanfactory。初始化beanfactory源码如下。
3.3、obtainFreshBeanFactory源码解析
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新beanfactory
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
3.4、refreshBeanFactory源码解析
protected final void refreshBeanFactory() throws BeansException {
//判断容器是否存在,已经有了一个容器,先销毁里面的bean然后再关闭容器,spring保证只有一个容器
if (hasBeanFactory()) {
destroyBeans();//销毁已经存在的bean
closeBeanFactory();//关闭bean工厂
}
try {
//创建IoC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
//对IOC容器进行初始化
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);
}
}
refreshBeanFactory中创建IOC容器,并对容器进行初始化,主要的方法为加载类。
3.5、loadBeanDefinitions源码解析
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建一个XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//配置XmlBeanDefinitionReader
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//初始化beanDefinitionReader
initBeanDefinitionReader(beanDefinitionReader);
//加载bean
loadBeanDefinitions(beanDefinitionReader);
}
从loadBeanDefinitions的源码中可以看到创建了一个XmlBeanDefinitionReader读取资源文件,加载资源文件中定义的类。继续跟踪loadBeanDefinitions最终找到XmlBeanDefinitionReader.java 中的registerBeanDefinitions
3.6、registerBeanDefinitions源码解析
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
这个方法是返回新加入的beanDefinition的个数,继续跟踪documentReader.registerBeanDefinitions,追踪到主要的方法为parseBeanDefinitions
3.7、parseBeanDefinitions源码解析
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//解析xml,获取bean
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
查看解析方法parseDefaultElement。
3.8、parseDefaultElement源码解析
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
//解析节点为bean的节点
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
3.9、processBeanDefinition源码解析
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析xml,获取bean
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//注册bean
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
至此,beanfactory初始化基本完成了。