我们知道Spring的可用通过多种方式进行配置:XML配置文件、Groovy配置文件、注解配置、Java代码配置。无论什么样的形式的配置都要先被解析成初始化Bean所需要的各种元信息(Metadata),也就是BeanDefinition对象。
上一个回合,我们提到BeanFactory已经被创建了,那紧接着,我们看到BeanDefinition就进行加载了,我们对着核心源码一一道来。
目前,我们就已经得到了一个BeanFactory对象,这之后,我们将使用BeanFactory实例完成一系列的后续工作。在refreshBeanFactory
中,则有非常重要的一步——loadBeanDefinitions(beanFactory)
,这里面的源码真的是很庞大,我们还是挑重点进行讲解。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为BeanFactory实例创建一个XmlBeanDefinitionReader实例,实际的BeanDefinition便是交给该实例来完成的
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 将Environment/资源加载器/XML的实体解析器设置到XmlBeanDefinitionReader实例上
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 执行核心的BeanDefinition加载逻辑
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
继续看 loadBeanDefinitions(beanDefinitionReader)
的核心逻辑
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
下面就进入了XmlBeanDefinitionReader
的加载逻辑中
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
for (String location : locations) {
count += loadBeanDefinitions(location);
}
return count;
}
加载多个资源,便有加载单个资源接口,直接看
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
// ignore
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
// ignore
return count;
}
catch (IOException ex) {
// ignore
}
}
else {
// ignore
}
}
转化成String location转化成 Resource之后继续下钻 - loadBeanDefinitions(resources)
并且会继续遍历后执行 loadBeanDefinitions(new EncodedResource(resource));
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// ignore
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
// ignore
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
// ignore
}
// ignore
}
EncodedResource加上了编码和字符集信息,继续下钻至 doLoadBeanDefinitions(inputSource, encodedResource.getResource())
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
// ignore
}
这里加上2个标题,之前都跳过也没有关系,核心的就是这里的逻辑:
将配置信息Resource读取成Document对象中,并根据该Document对象将资源注册到Bean工厂中
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 专门处理
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// registry就是BeanFactory(实现了BeanDefinitionRegistry)
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
继续看,又是将处理逻辑委托给BeanDefinitionDocumentReader
实例的方法 registerBeanDefinitions,搞不清这是装饰器模式,还是适配器模式,还是代理模式。。。
先看DefaultBeanDefinitionDocumentReader
的实现吧
protected void doRegisterBeanDefinitions(Element root) {
// ignore
this.delegate = createDelegate(getReaderContext(), root, parent);
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// <bean 使用的是默认的namespace,进入该分支
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 {
// ignore
}
}
又是委托给BeanDefinitionParserDelegate
来干剩下的活,是一层层做增强,但也不是装饰器模式吧,没有统一的契约额。算了,继续向下看吧
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 Node的加载逻辑完事了
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 这儿重点,document解析成BeanDefinition就是这儿完成的!
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 又继续向下交给BeanDefinitionReaderUtils工具类的静态方法来处理额
// 参数就是BeanDefinition的持有器和BeanFactory这个BeanDefintion注册器
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
// ignore
}
}
进去看下
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 狗日的,兜一大圈回来,还是交给BeanFactory这个BeanDefintion注册器来完成注册
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
// 有别名的话,也注册上
registry.registerAlias(beanName, alias);
}
}
}
我们在上面铁锅BeanFactory的类图,实现了BeanDefinitionRegistry和AliasRegistry,所以传进来的就是BeanFactory对象了
回到BeanFactory再看,BeanDefinition是怎么被加载的,进入org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
// ignore
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
// ignore
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
// ignore
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
// 维护一个MAP beanName to beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
// 所有的beanDefinition名称
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
这里的逻辑就蛮简单的,BeanDefinition列表都已经拿到了,就注册上去好了(忽略的和没有提到的代码无非就是检查重复、判断是否已经有同名的单例Bean存在了,都销毁、刷新或重置下)
至此,就完成了BeanFactory的实例化,基础设置工作和BeanDefinition加载工作,因为笔者使用的是XML的配置文件,在最终的BeanDefinition加载前经过XmlBeanDefinitionReader中的BeanDefinitionDocumentReader处理,并交由BeanDefinitionParserDelegate完成配置资源加载成Document并解析成BeanDefinition,并由BeanDefinitionReaderUtils调用BeanDefinitionRegistry实例(也就是BeanFactory实例)完成BeanDefinition的注册。