Spring IOC 实现原理(下)

Spring IOC 实现原理

本文分两部分,第一部分略讲,简要地说明整个流程;第二部分详细讲解

下面来让大家了解一下 Spring 到底是怎么运行的。

Java 代码

public static void main(String[] args) {
		ApplicationContext context = new FileSystemXmlApplicationContext(
				"applicationContext.xml");
		Animal animal = (Animal) context.getBean("animal");
		animal.say();
	}

这段代码你一定很熟悉吧,不过还是让我们分析一下它吧,首先是 applicationContext.xml

<bean id="animal" class="phz.springframework.test.Cat">
		<property name="name" value="kitty" />
	</bean>

他有一个类 phz.springframework.test.Cat

public class Cat implements Animal {
	private String name;
	public void say() {
		System.out.println("I am " + name + "!");
	}
	public void setName(String name) {
		this.name = name;
	}
}

实现了 phz.springframework.test.Animal 接口

public interface Animal {
	public void say();
}

很明显上面的代码输出 I am kitty!
那么到底 Spring 是如何做到的呢?
接下来就让我们自己写个 Spring 来看看 Spring 到底是怎么运行的吧!
首先,我们定义一个 Bean 类,这个类用来存放一个 Bean 拥有的属性

/* Bean Id */
	private String id;
	/* Bean Class */
	private String type;
	/* Bean Property */
	private Map<String, Object> properties = new HashMap<String, Object>();

一个 Bean 包括 id,type, 和 Properties。
接下来 Spring 就开始加载我们的配置文件了,将我们配置的信息保存在一个 HashMap 中,HashMap 的 key 就是 Bean 的 Id ,HasMap 的 value 是这个 Bean,只有这样我们才能通过 context.getBean("animal") 这个方法获得 Animal 这个类。我们都知道 Spirng 可以注入基本类型,而且可以注入像 List,Map 这样的类型,接下来就让我们以 Map 为例看看 Spring 是怎么保存的吧
Map 配置可以像下面的**

<bean>
		<property name="testMap">
			<map>
				<entry key="a">
					<value>1</value>
				</entry>
				<entry key="b">
					<value>2</value>
				</entry>
			</map>
		</property>
	</bean>

Spring 是怎样保存上面的配置呢?,代码如下:

if (beanProperty.element("map") != null) {
					Map<String, Object> propertiesMap = new HashMap<String, Object>();
					Element propertiesListMap = (Element) beanProperty
							.elements().get(0);
					Iterator<?> propertiesIterator = propertiesListMap
							.elements().iterator();
					while (propertiesIterator.hasNext()) {
						Element vet = (Element) propertiesIterator.next();
						if (vet.getName().equals("entry")) {
							String key = vet.attributeValue("key");
							Iterator<?> valuesIterator = vet.elements()
									.iterator();
							while (valuesIterator.hasNext()) {
								Element value = (Element) valuesIterator.next();
								if (value.getName().equals("value")) {
									propertiesMap.put(key, value.getText());
								}
								if (value.getName().equals("ref")) {
									propertiesMap.put(key, new String[] { value
											.attributeValue("bean") });
								}
							}
						}
					}
					bean.getProperties().put(name, propertiesMap);
				}

接下来就进入最核心部分了,让我们看看 Spring 到底是怎么依赖注入的吧,其实依赖注入的思想也很简单,它是通过反射机制实现的,在实例化一个类时,它通过反射调用类中 set 方法将事先保存在 HashMap 中的类属性注入到类中。让我们看看具体它是怎么做的吧。
首先实例化一个类,像这样

public static Object newInstance(String className) {
		Class<?> cls = null;
		Object obj = null;
		try {
			cls = Class.forName(className);
			obj = cls.newInstance();
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		} catch (InstantiationException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
		return obj;
	}

接着它将这个类的依赖注入进去,像这样

public static void setProperty(Object obj, String name, String value) {
		Class<? extends Object> clazz = obj.getClass();
		try {
			String methodName = returnSetMthodName(name);
			Method[] ms = clazz.getMethods();
			for (Method m : ms) {
				if (m.getName().equals(methodName)) {
					if (m.getParameterTypes().length == 1) {
						Class<?> clazzParameterType = m.getParameterTypes()[0];
						setFieldValue(clazzParameterType.getName(), value, m,
								obj);
						break;
					}
				}
			}
		} catch (SecurityException e) {
			throw new RuntimeException(e);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException(e);
		}
}

最后它将这个类的实例返回给我们,我们就可以用了。我们还是以 Map 为例看看它是怎么做的,我写的代码里面是创建一个 HashMap 并把该 HashMap 注入到需要注入的类中,像这样,

if (value instanceof Map) {
				Iterator<?> entryIterator = ((Map<?, ?>) value).entrySet()
						.iterator();
				Map<String, Object> map = new HashMap<String, Object>();
				while (entryIterator.hasNext()) {
					Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next();
					if (entryMap.getValue() instanceof String[]) {
						map.put((String) entryMap.getKey(),
								getBean(((String[]) entryMap.getValue())[0]));
					}
				}
				BeanProcesser.setProperty(obj, property, map);
			}

好了,这样我们就可以用 Spring 给我们创建的类了,是不是也不是很难啊?当然 Spring 能做到的远不止这些,这个示例程序仅仅提供了 Spring 最核心的依赖注入功能中的一部分。
本文参考了大量文章无法一一感谢,在这一起感谢,如果侵犯了你的版权深表歉意,很希望对大家有帮助!**


Spring IOC 实现原理

IOC: Inversion of Control , 即 "控制反转" , 不是什么技术,而是一种思想。原先需要自行实例化的对象, 交给 IOC 容器去实现。那么控制反转,谁被控制? 谁被反转 ?

在传统的 JavaSE 程序中,直接在类的内部通过 new 关键字来创建对象的实例,是程序主动去创建依赖对象,而 IOC 有一个专门的容器,来创建这些对象,由 IOC 容器来控制对象的创建,依赖对象也是容器帮忙查找创建并进行注入,对象只是被动的接受,依赖对象的获取被反转了。它还有一个更加形象的名字叫 依赖注入。

注入方式:

  • 接口注入
  • setter
  • 构造器注入

IOC 容器的设计与实现有两种:BeanFactory 和 ApplicationContext

IOC 容器的两个容器设计系列:

  • 实现了 BeanFactory 接口的简单容器系列,只是实现了容器最基本的功能
  • ApplicationContext 应用上下文,作为容器的高级形态存在。除了具有基本的功能外,还增加了许多面向框架的特性,同时对应用环境做了许多适配。

BeanFactory

BeanFactory 为 IOC 容器具体实现指定了基本的规范,换句话说 BeanFactory 是最顶层的类,它有三个子类,ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory 接口。但是它们最终生成了一个默认的实现类 DefaultListableBeanFactory。类的继承关系如下:

img

​ BeanFactory 继承关系图. png

上图中 DefaultListableBeanFactory 的继承关系并不完整,删除了 AliasRegistry 接口的相关信息。

下面看一下 BeanFactory 接口中关于方法的定义:

public interface BeanFactory {
    
    String FACTORY_BEAN_PREFIX = "&";
    
    Object getBean(String var1) throws BeansException;
    
    <T> T getBean(String var1, Class<T> var2) throws BeansException;
    
    <T> T getBean(Class<T> var1) throws BeansException;
    
    Object getBean(String var1, Object... var2) throws BeansException;
    
    boolean containsBean(String var1);
    
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
    
    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
    
    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
    
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
    
    String[] getAliases(String var1);
}

通过对上面方法的分析,可以得出。BeanFactory 并不关心 bean 是如何定义,怎样被加载的,当我们需要 bean 的时候,直接来取就可以了。对于工厂来说,我只需要关心有没有产品,对于产品是怎么产生,怎么制作的,那是工人干的事,工厂并不关心。定义的都是最核心的接口,如 getBean(),从容器中获取实例

ApplicationContext

ApplicationContext 是 Spring 提供的一个高级的 IOC 容器,除了提供基本 IOC 容器的功能外,还能为用户提供:

  • 支持信息源,可以实现国际化
  • 访问资源
  • 支持应用事件
  • ApplicationContext 中提供的附加服务

看一下 ApplicationContext 的继承关系。

img

​ AppliciationContext 继承关系图. png

通过对上图的分析,可以看出 ApplicationContext 除了 BeanFactory 的功能,还具有 ResourceLoader 接口的功能,具有了高级容器特性的支持。

下面对接口的继承关系做一个简要的分析:

  • 在 BeanFactory 中,从 BeanFactory 到 HierarchicalBeanFactory, 再到 ConfigurableBeanFactory, 是一个条主要的设计路径。 BeanFactory 中定义了基本的 IOC 容器规范,在 HierarchicalBeanFactory 接口中增加了 getparantBeanFactory() 的接口功能,使 BeanFactory 具备了双亲 IOC 容器的管理功能,在 ConfigurableBeanFactory 主要定义了一些对 BeanFactory 的配置功能
  • 在 ApplicationContext 中,从 BeanFactory 到 ListableBeanFactory, 再到 ApplicationContext, 再到常用的 WebApplicationContext 或者 ConfigurableApplicationContext 接口。在 BeanFactory 简单接口的基础上增加了对高级容器的特性支持。

BeanDefinition
SpringIOC 容器帮我们管理了各种 bean 对象及其相互依赖的关系,**Bean 对象在 Spring 实现中是以 BeanDefinition 来描述的。* *
换句话说 依赖关系是使用 BeanDefinition 来保存的。 其继承体系如下:

img

BeanDefinition 继承关系图. png

Spring 关于 Bean 的装配,有下面三种方式:

  • 在 XML 中进行显示配置
  • 在 java 中进行显示配置
  • 隐式的 bean 发现机制和自动装配

Bean 的解析非常的复杂,功能被分的很细,需要扩展的地方也很多,必须保证有足够的灵活性,下面看一下基于 xml 配置文件解析的继承体系:

img

XmlBeanDefinitionReader 的继承关系图. png

IOC 容器的初始化

IOC 容器的初始化包括:BeanDefinition 的 Resouce 定位,BeanDefinition 的载入和注册三个基本的过程。需要注意的是 Spring 把上面过程进行了分离,并使用了不同的模块来完成,定位使用了 ResourceLoader, 解析使用了 BeanDefinitionReader 等。这样设计的目的可以让用户对这三个过程进行裁剪和扩展,定义出适合自己的 IOC 容器初始化过程。

下面来看一下两种 IOC 容器的创建过程,BeanFactory 以 XmlBeanFactory 为例,ApplicationContext 以 FileSystemXmlApplicationContext 为例

XmlBeanFactroy

看一下 XmlBeanFactory 的源码定义:

public class XmlBeanFactory extends DefaultListableBeanFactory {
    
    private final XmlBeanDefinitionReader reader;
    
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, (BeanFactory)null);
    }
    
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader = new XmlBeanDefinitionReader(this);
        this.reader.loadBeanDefinitions(resource);
    }
}

通过阅读 XmlBeanFactory 的源码可以看出。

XmlBeanFactory 继承自 DefaultListableBeanFactory 类。而 DefaultListableBeanFactory 类包含了基本 IOC 容器所具有的重要功能。

那 BeanDefinition 的信息来源自哪, 如何定位? 定位之后又如何读取解析呢??

对于信息来源的定位封装成 Spring 中的 Resource 类来给出,解析是它的内部定义了一个 XmlBeanDefinitionReader 对象,有了这个对象,就有了处理 xml 文件的能力。

参考 XmlBeanFactory 的实现,我们手动来模拟一下 XmlBeanFactory 的实现过程

ClassPathResource res = new ClassPathResource("beans.xml");

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(res);

通过上面的代码,总结一下 IOC 容器的使用步骤:

  • 创建 IOC 抽象资源,这个抽象资源包含了 BeanDefinition 的定义信息
  • 创建一个 BeanFactory
  • 创建一个 BeanDefinition 的读取器,通过一个回调配置给 BeanFactory
  • 从定义好的抽象资源中读取配置信息。完成载入和注册的定义后,IOC 容器就建立了起来了。

FileSystemXmlApplicationContext

先来看一下 FileSystemXmlApplicationContext 的继承关系:

img

image.png

通过上面的继承关系,可以发现它的基类 AbstractXmlApplicationContext 中已经实现了主要的功能。

在看一下这个类的源码实现,关于构造方法部分,我做了删减:

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

    
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if(refresh) {
            this.refresh();
        }
    }
    
    protected Resource getResourceByPath(String path) {
        if(path != null && path.startsWith("/")) {
            path = path.substring(1);
        }
        return new FileSystemResource(path);
    }
}

除了构造方法和 getResourceByPath 外,并没有其他的方法。也就说它只是实现了和它自身设计相关的两个功能。

看一下该类的调用方式:

ApplicationContext context =new FileSystemXmlApplicationContext(xmlPath);

上面调用了参数是字符串的构造函数, 但是,对构造函数的调用最终都会转到下面的方法来执行,refresh 方法启动了整个容器的初始化流程:

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

来看一下上面的构造方法中,最终都执行了那些操作,具体的操作都是由那些类执行的。
通过代码跟随,可以发现,super(parent) 这个方法最终是由其基类(AbstractApplicationContext)来执行,执行了 AbstractApplicationContext 的无参构造方法和 setParent()方法。其代码如下,省略了静态代码块的定义:

public AbstractApplicationContext(ApplicationContext parent) {
    this();
    setParent(parent);
}

public AbstractApplicationContext() {
    this.resourcePatternResolver = getResourcePatternResolver();
}

protected ResourcePatternResolver getResourcePatternResolver() {
    return new PathMatchingResourcePatternResolver(this);
}

public void setParent(ApplicationContext parent) {
    this.parent = parent;
    if (parent != null) {
        Environment parentEnvironment = parent.getEnvironment();
        if (parentEnvironment instanceof ConfigurableEnvironment) {
            getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
        }
    }
}

调用父类的构造方法执行完成后,返回 FileSystemXmlApplicationContext 类,执行 setConfigLocations(configLocations) 方法,该方法的定义在类 AbstractRefreshableConfigApplicationContext 中:

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

在资源定位的时候,支持下面两种方式:

  • ClasspathResource res = new ClasspathResource("a.xml,b.xml");
  • ClasspathResource res = new ClasspathResource("new String(){'a.xml','b.xml'}")

具体实现的方式不在展开,感兴趣的可以去看一下源码实现

我们来看以上,程序执行到此处后,都做了哪些操作:

  1. 在 AbstractApplicationContext 中初始化了 resourcePatternResolver(多资源文件的载入),用于获取 Resource,关于何时使用后面再解释
  2. 将资源的定义路径保存在了 configLocations 数组中

到此,IOC 容器根据资源定义路径获取 Resouce 的准备工作便完成了。

IOC 容器的初始化过程

在开始分析初始化过程之前,先从宏观上对初始化的过程做一个简单的介绍,有一个大体框架的初始化模型,方便后面的理解,初始化过程分成了三个过程:

  • Resource 定位
  • BeanDefinition 的载入
  • 向 IOC 容器注册这些 BeanDefinition 信息。这个过程是通过 BeanDefinitionRegistry 接口的实现来完成的。最终注入到 HashMap 中去,这个 hashmap 就是持有 beandefinition 数据的。

下面来看一下 FileSystemXmlApplicationContext 中的关于 refresh() 方法的调用,实际调用的是 AbstractApplicationContext 中的 refresh() 方法,该方法定义如下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        
        prepareRefresh();
        
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        
        prepareBeanFactory(beanFactory);
        try {
            
            postProcessBeanFactory(beanFactory);
            
            invokeBeanFactoryPostProcessors(beanFactory);
            
            registerBeanPostProcessors(beanFactory);
            
            initMessageSource();
            
            initApplicationEventMulticaster();
            
            onRefresh();
            
            registerListeners();
            
            finishBeanFactoryInitialization(beanFactory);
            
            finishRefresh();
        }catch (BeansException ex) {
            
            destroyBeans();
            
            cancelRefresh(ex);
            
            throw ex;
        }
    }
}

refresh()方法主要为 IOC 容器 Bean 的生命周期提供管理条件。Spring IOC 容器的生成是从 refreshBeanFactory()方法开始的,也就是执行了下面的代码:

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

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

在 AbstractApplicationContext 抽象类中,只是进行了 refreshBeanFactory() 方法的定义,方法的实现是在其子类 AbstractRefreshableApplicationContext 中实现的,在子类的定义如下:

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

上面代码 loadBeanDefinitions(beanFactory); 我们说是一个委派模式,只是进行了方法的定义,具体实现则是由 AbstractXmlApplicationContext 类实现,在该方法中创建了读取器 XmlBeanDefinitionReader 的实例, 然后把这个读取器在 IOC 容器中设置好,最后是启动读取器来完成对 BeanDefinition 在 IOC 容器中的载入,定义如下:

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    
    
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
    beanDefinitionReader.setResourceLoader(this);
    
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
    initBeanDefinitionReader(beanDefinitionReader);
    
    loadBeanDefinitions(beanDefinitionReader);
}

在 XmlBeanDefinitionReader 的初始化过程中,还进行了一些其他的操作,具体如下:

public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
    super(registry);
}

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
    
    this.registry = registry;
    
    if (this.registry instanceof ResourceLoader) {
        this.resourceLoader = (ResourceLoader) this.registry;
    }
    else {
        
        this.resourceLoader = new PathMatchingResourcePatternResolver();
    }
    
    if (this.registry instanceof EnvironmentCapable) {
        this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
    }
    else {
        
        this.environment = new StandardEnvironment();
    }
}

通过上面代码发现,在创建 XmlBeanDefinitionReader 的过程中,完成了 resourceLoader 和 eviironment 的赋值操作。

首先得到 BeanDefinition 信息的 Resource 定位,然后直接调用 XmlBeanDefinitionReader 来读取,具体的载入过程是委托给 BeanDefinitionReader 来完成的。因为使用的 FileSystemXmlApplicationContext, getConfigResources() 方法返回的是 null, 所以程序会走第二个分支

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        
        reader.loadBeanDefinitions(configResources);
    }
    
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinition(configLocations);
    }
}

程序分析到这,来梳理一下上面的执行流程。

  • 在 FileSystemXmlApplicationContext 一共做了三件事
    • 调用了父类的构造器,进行了初始化
    • 设置了 BeanDefinition 的定义路径
    • 执行了 Refresh() 方法
  • refresh() 方法来启动整个 BeanDefinition 的载入过程
    • 创建容器 DefaultListableBeanFactory
    • 创建了 XmlXmlBeanDefinitionReader
    • 开始准备通过 reader 来加载资源

AbstractBeanDefinitionReader 读取 Bean 定义资源,AbstractBeanDefinitionReader 的 loadBeanDefinitions 方法源码如下:

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    int counter = 0;
    String[] var3 = locations;
    int var4 = locations.length;
    for(int var5 = 0; var5 < var4; ++var5) {
        String location = var3[var5];
        counter += this.loadBeanDefinitions(location);
    }
    return counter;
}
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
    return this.loadBeanDefinitions(location, (Set)null);
}

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
    
    
    
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
        throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
    }
    
    if (resourceLoader instanceof ResourcePatternResolver) {
        try {
            
            
            Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
            
            int loadCount = loadBeanDefinitions(resources);
            if (actualResources != null) {
                for (Resource resource : resources) {
                    actualResources.add(resource);
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
            }
            return loadCount;
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);
        }
    }
    else {
        
        Resource resource = resourceLoader.getResource(location);
        int loadCount = loadBeanDefinitions(resource);
        if (actualResources != null) {
            actualResources.add(resource);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
        }
        return loadCount;
    }
}

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        Resource[] var3 = resources;
        int var4 = resources.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Resource resource = var3[var5];
            counter += this.loadBeanDefinitions((Resource)resource);
        }

        return counter;
    }

上面的方法主要进行了两件事:

  • 调用资源加载器获取资源 resourceLoader.getResource(location)
  • 真正执行加载功能的是子类 XmlBeanDefinitionReader 的 loadBeanDefinitions 方法

loadBeanDefinitions() 方法在 AbstractBeanDefinitionReader 中并没有具体的实现,它会转到 XmlBeanDefinitionReader 中的 loadBeanDefinitions(Resource resource) 中运行:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    
    return this.loadBeanDefinitions(new EncodedResource(resource));
}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if(this.logger.isInfoEnabled()) {
        this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
    }
    Object currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
    if(currentResources == null) {
        currentResources = new HashSet(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }
    if(!((Set)currentResources).add(encodedResource)) {
        throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    } else {
        int var5;
        try {
            
            InputStream ex = encodedResource.getResource().getInputStream();
            try {
                
                InputSource inputSource = new InputSource(ex);
                
                if(encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                
                var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            } finally {
                ex.close();
            }
        } catch (IOException var15) {
            throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
        } finally {
            ((Set)currentResources).remove(encodedResource);
            if(((Set)currentResources).isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
        return var5;
    }
}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {
        try {
            
            Document doc = doLoadDocument(inputSource, resource);
            
            return registerBeanDefinitions(doc, resource);
        }
        
        catch (....) {
            throw ex;
        }
    }

将 XML 文件转换成 Document 对象,解析过程由 documentLoader 实现,getValidationModeForResource(resource)验证 xml 文件的模式 DTD 还是 XSD,此方法不在展开。

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource,getEntityResolver(), this.errorHandler,getValidationModeForResource(resource),isNamespaceAware());
    }

创建 Document 的过程:

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
    
    DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    if (logger.isDebugEnabled()) {
        logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
    }
    
    DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    
    return builder.parse(inputSource);
}

spring 并没有对 XML 进行特殊的处理,使用了 SAX 对 xml 文档进行解析,操作分为三步:

  • 创建 DocumentBuilderFactory
  • 创建 DocumentBuilder
  • 解析 inputSource 对象,返回 Document 对象

Document 对象代表了一个 XML 文档的模型树,所有的其他 Node 都以一定的顺序包含在 Document 对象之内,排列成一个树状结构,以后对 XML 文档的所有操作都与解析器无关,直接在这个对象上操作即可。NodeList 代表了包含一个或者多个 Node 的列表,操作上可以看作数组,使用 getLength() 获得列表中的节点数,item(int index) 返回集合中第 index 个项。Node 对象很少使用,会使用它的自对象 Element,Attr 等。

至此,Spring IOC 容器根据定位的 Bean 定义资源文件,并将其加载读入转换为 document 对象的过程完成。

上面略微呢有一点跑题,document 对象的创建过程可能不是我们最关心的,我们关心就是 Spring 的 BeanDefinition 是怎样按照 Spring 的 Bean 语义要求进行解析并转化为容器内部数据结构的。 这个过程是在下面的方法中执行的,我们来看一下,具体的操作过程:

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

Bean 定义资源的解析分为以下两个过程:

  • 通过调用 xml 解析器,将资源定义文件转换为 Document 对象,document 对应并没有按照 spring bean 的规则进行解析。
  • 在完成通用 xml 解析之后,按照 Spring 的 Bean 规则对 Document 对象进行解析,这个过程是在 documentReader 中实现的。具体的操作是由 DefaultBeanDefinitionDocumentReader 完成的。
    处理的结果由 BeanDefinitionHolder 对象持有。解析过程由 BeanDefinitionParserDelegate 来实现。

来看下面的流程:

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    
    Element root = doc.getDocumentElement();
    doRegisterBeanDefinitions(root);
}

protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    
    
    this.delegate = createDelegate(getReaderContext(), root, parent);
    
    if (this.delegate.isDefaultNamespace(root)) {
        
        
        
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +"] not matching: " + getReaderContext().getResource());
                    }
                    return;
            }
        }
    }
    
    
    preProcessXml(root);
    
    parseBeanDefinitions(root, this.delegate);
    
    postProcessXml(root);
    this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
    BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
    delegate.initDefaults(root, parentDelegate);
    return delegate;
}

解析 document 文件,不同的命名的空间采用不同的方法处理

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)) {
                    
                    parseDefaultElement(ele, delegate);
                }
                else {
                    
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        
        delegate.parseCustomElement(root);
    }
}

使用 spring 的 Bean 规则解析 Document 元素节点,有些元素节点是 等,则分别进行解析

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)) {
        processBeanDefinition(ele, delegate);
    }
    
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            
        doRegisterBeanDefinitions(ele);
    }
}

主要看一下对 bean 标签的解析过程。

protected void processBeanDefinition(Element ele,BeanDefinitionParserDelegate delegate) {
    
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            ....
        }
        
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

下面看一下 parseBeanDefinitionElement()方法的具体实现, 对于 BeanDefinition 的注册时存放在 ConcurrentHashMap 中的,beanName 变为存放的健:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    
    String id = ele.getAttribute(ID_ATTRIBUTE);
    
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    
    List<String> aliases = new ArrayList<String>();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
    }
    
    String beanName = id;
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
            logger.debug("....");
        }
    }

    if (containingBean == null) {
        checkNameUniqueness(beanName, aliases, ele);
    }
    
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    
                    beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("....");
                }
            }
            catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }
    return null;
}

BeanDefinition 可以看成是对 定义的抽象,这个数据对象中封装的数据大多都是与 < bean > 定义相关的,也有很多就是我们在定义 Bean 时看到的那些 Spring 标记。这个 BeanDefinition 数据类型是非常重要的,它封装了很多基本数据,这些都是 Ioc 容器需要的,上面代码最后我们返回了一个 BeanDefinitionHolder 实例,这个实例封装了 beanDefinition,beanName, aliase 三个信息,beanDefinition 中也包含了 beanName,aliase 信息。

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {

    this.parseState.push(new BeanEntry(beanName));
    
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }

    try {
        
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        
        
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
        
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        
        parseMetaElements(ele, bd);
        
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        
        parseConstructorArgElements(ele, bd);
        
        parsePropertyElements(ele, bd);
        
        parseQualifierElements(ele, bd);

        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));
        
        return bd;
    }
    catch (ClassNotFoundException ex) {
        ...
    }
    catch (NoClassDefFoundError err) {
        ...
    }
    catch (Throwable ex) {
        ...
    }
    finally {
        this.parseState.pop();
    }
    return null;
}

从上面的代码可以看出,要解析属性首先要创建用于承载属性的实例,也就是创建 GenericBeanDefinition 类型的实例,而代码 createBeanDefinition(className,parent) 的作用就是实现此功能。创建完承接的实例后,便可以进行各种属性的解析了,首先进行解析的是在 < bean> 标签中定义的各种属性,如 scope, singleton,abstract,lazy-init 等,然后再解析子标签中的属性,如:lookup-method ,constructor-arg 等。解析完成之后关联到实例上,之所以能进行关联,是因为 xml 中所有的配置都能在 GenericBeanDefinition 的实力类中找到对应的配置。 此时容器还没有起作用,要想起作用,需要向容器进行注册。

分析到这,已经完成了 xml 文件向 BeanDefinition 的转化,每个一个 标签都会转化成一个 BeanDefinition 对应的实体。实体中包含了 < bean > 中定义的所有属性。

BeanDefinition 在 IOC 容器中的注册

前面只是进行了 BeanDefinition 在 IOC 容器中的载入和解析过程,这些动作完成后,已经完成了定义的数据转化为 BeanDefinition 的过程。下面代码继续执行,看一下注册的过程,也就是 processBeanDefinition 函数中的 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry()) 的代码。

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {

    
    String beanName = definitionHolder.getBeanName();
    
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            
            registry.registerAlias(beanName, alias);
        }
    }
}

最终承接注册任务方法是在 DefaultListableBeanFactory 类中定义的,为了更好的排版,我对下面的代码进行了删减,主要删除了抛出异常信息和日志信息,并不影响代码的逻辑,对于 beanDefinition 的注册,做了一些验证之后,直接将 beanDefinition 放入了 Map 中:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {
    
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
             
            
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            ....
        }
    }

    BeanDefinition oldBeanDefinition;
    
    oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    if (oldBeanDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
                throw ...
            }
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("....");
                }
            }
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("....");
                }
            }
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("...");
                }
            }
            
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {

            
            
            if (hasBeanCreationStarted()) {
                
                synchronized (this.beanDefinitionMap) {
                    
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            else {
                
                
                this.beanDefinitionMap.put(beanName, beanDefinition);
                
                this.beanDefinitionNames.add(beanName);
                
                this.manualSingletonNames.remove(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

至此,Bean 定义资源文件中配置的 Bean 被解析过后,已经注册到 IoC 容器中,被容器管理起来,真正完成了 IoC 容器初始化所做的全部工作。现 在 IoC 容器中已经建立了整个 Bean 的配置信息,这些 BeanDefinition 信息已经可以使用,并且可以被检索,IoC 容器的作用就是对这些注册的 Bean 定义信息进行处理和维护。这些的注册的 Bean 定义信息是 IoC 容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。

依赖注入

执行完上面的操作后,IOC 容器已经实现了对 Bean 管理定义的相关数据,但是此时 IOC 容器还没有对所管理的 Bean 进行依赖注入,依赖注入在以下两种情况下发生:

  • 用户第一次通过 getBean() 方法想容器索取时,进行依赖注入
  • 当用户在 Bean 的定义中为 配置了 lazy-init 属性,让容器在解析注册时进行欲初始化,触发依赖注入

AbstactBeanFactory 通过 getBean() 函数获取被管理的 Bean,但是因为 lazyinit 默认为 false, 所以 spring 会进行部分实例的初始化操作,让我们回退到 AbstactApplicationContext 类的 finishBeanFactoryInitialization(beanFactory) 方法,该方法进行了所有单例类的初始化操作,初始化的动作包装在了 getBean() 方法中,这个方法是获取 Bean 的地方,也是依赖注入发生的地方, 对 genBean 的调用会转入到 doGetBean() 方法来执行, 来看一下该方法的定义:

protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {
    
    final String beanName = transformedBeanName(name);
    
    Object bean;

    
    Object sharedInstance = getSingleton(beanName);
    
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("...");
            }
            else {
                logger.debug("...");
            }
        }
        
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
        
        if (isPrototypeCurrentlyInCreation(beanName)) {
            
            throw new BeanCurrentlyInCreationException(beanName);
        }
        
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            
            String nameToLookup = originalBeanName(name);
            if (args != null) {
                
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }
        
        if (!typeCheckOnly) {
            
            markBeanAsCreated(beanName);
        }
        try {
            
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            
            
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(。。。);
                    }

                    
                    registerDependentBean(dep, beanName);
                    
                    getBean(dep);
                }
            }

            
            if (mbd.isSingleton()) {
                
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        try {
                            
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            
            else if (mbd.isPrototype()) {
                
                Object prototypeInstance = null;
                try {
                    
                    beforePrototypeCreation(beanName);
                    
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    
                    afterPrototypeCreation(beanName);
                }
                
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            
            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("...");
                }
                try {
                    
                    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        beforePrototypeCreation(beanName);
                        try {
                                return createBean(beanName, mbd, args);
                        }
                        finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(...);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
    
    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
        try {
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug(....);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    
    return (T) bean;
}

OK, 上面的流程走完了,接下来该分析分支方法了, 没错,就是那个方法 crateBean(), 其定义如下:

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            
            
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }
        
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }

继续来看 doCreateBean()方法:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)throws BeanCreationException {

        
        BeanWrapper instanceWrapper = null;
        
        if (mbd.isSingleton()) {
            
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null):
        mbd.resolvedTargetType = beanType;

        
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        
        
        
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        
        Object exposedObject = bean;
        try {
            
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {

                
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(。。。);
                    }
                }
            }
        }

        
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(。。。);
        }

        return exposedObject;
    }

到此,doCreateBean 方法便执行完了,上面的方法主要执行了三个步骤:

  • 创建 Bean 实例 createBeanInstance 方法
  • 依赖注入 populateBean 方法
  • 回调方法 initializeBean

下面介绍与依赖注入关系特别密切的方法 createBeanInstance 和 populateBean 方法。这个方法的主要作用就是实例化我们指定的类。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
        
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
        
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(....);
        }

        if (mbd.getFactoryMethodName() != null)  {
            
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }

        
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            if (autowireNecessary) {
                
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                
                return instantiateBean(beanName, mbd);
            }
        }

        
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null ||
                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            
            return autowireConstructor(beanName, mbd, ctors, args);
        }

        
        return instantiateBean(beanName, mbd);
    }

在创建实例时,重要的是下面代码:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

继续跟进一下:

public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
        
        if (bd.getMethodOverrides().isEmpty()) {
            Constructor<?> constructorToUse;
            synchronized (bd.constructorArgumentLock) {
                constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse == null) {
                    final Class<?> clazz = bd.getBeanClass();
                    if (clazz.isInterface()) {
                        throw new BeanInstantiationException(clazz, "Specified class is an interface");
                    }
                    try {
                        if (System.getSecurityManager() != null) {
                            constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
                                @Override
                                public Constructor<?> run() throws Exception {
                                    return clazz.getDeclaredConstructor((Class[]) null);
                                }
                            });
                        }
                        else {
                            constructorToUse =  clazz.getDeclaredConstructor((Class[]) null);
                        }
                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    }
                    catch (Throwable ex) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                    }
                }
            }
            return BeanUtils.instantiateClass(constructorToUse);
        }
        else {
            
            return instantiateWithMethodInjection(bd, beanName, owner);
        }
    }

判断一下是否存在方法覆写,如果不存在就使用 java 反射的方式创建实例,否则使用 CGLIB 来创建实例。

在这简单说一下,spring 创建 Bean 的两种方式,一种是通过 BeanUtis(JVM 的反射功能,必须要基于接口才能实现),另一种就是 CGLIB 来生成。具体的不做深入分析,会放入 AOP 中来说明。到这实例的创建就完成了, 下面说一下属性的注入.

bean 属性注入,上面的代码已经完成了 Bean 对象的实例化,实例化对象已经生成,怎样把这些 Bean 对象的依赖关系处理好,依赖关系已经保存在了 BeanDefinition 中,看下面的方法:

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
   
   PropertyValues pvs = mbd.getPropertyValues();
   
   if (bw == null) {
      
      if (!pvs.isEmpty()) {
         throw new BeanCreationException(。。。);
      }
      else {
         return;
      }
   }
 
   
   
   boolean continueWithPropertyPopulation = true;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }
 
   if (!continueWithPropertyPopulation) {
      return;
   }
    
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
 
      
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
 
      
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }
 
      pvs = newPvs;
   }
 
   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
 
   if (hasInstAwareBpps || needsDepCheck) {
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      if (hasInstAwareBpps) {
         for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
               InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
               
               
               pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvs == null) {
                  return;
               }
            }
         }
      }
      if (needsDepCheck) {
         checkDependencies(beanName, mbd, filteredPds, pvs);
      }
   }
   
   applyPropertyValues(beanName, mbd, bw, pvs);
}

initializeBean
属性注入完成后,这一步其实就是处理各种回调了。

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
            invokeAwareMethods(beanName, bean);
            return null;
         }
      }, getAccessControlContext());
   }
   else {
      
      invokeAwareMethods(beanName, bean);
   }
 
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
 
   try {
      
      
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
 
   if (mbd == null || !mbd.isSynthetic()) {
      
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}
posted @ 2020-03-29 15:29  别再闹了  阅读(72)  评论(0)    收藏  举报