版本 Spring Framework 6.0.9
1. 前言
了解过refresh大致流程后,紧接着上一篇文章,继续浅析下ClassPathXmlApplicationContext实例化过程的第三部分refresh()。
public class Main {
public static void main(String[] ags) {
// 创建ioc容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
}
}
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 调用基类AbstractApplicationContext构造方法,创建资源路径解析器,默认值是ResourcePatternResolver
super(parent);
// 设置上下文的配置路径
setConfigLocations(configLocations);
if (refresh) {
// 调用父类AbstractApplicationContext的refresh方法
refresh();
}
}
// 省略其他代码...
}
在示例中,main方法使用的ClassPathXmlApplicationContext的有参构造,refresh缺省值是true,默认调用refresh()方法。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 调用refreshBeanFactory方法来刷新当前Application的BeanFactory,由子类实现,该实例包含了所有的Bean定义信息,可以用于创建和管理Bean对象
refreshBeanFactory();
// 返回刷新后的BeanFactory实例,由子类实现,该实例可以用于后续的Bean操作,如获取Bean,注册Bean后置处理器,初始化消息源等
return getBeanFactory();
}
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
// 省略其他代码...
}
父类AbstractApplicationContext对refresh方法做了基本实现,也会调用子类重写的方法来完成整个刷新功能,下面主要关注refresh中obtainFreshBeanFactory阶段的模板方法,refresh的其他阶段基本是AbstractApplicationContext的代码。
ClassPathXmlApplicationContext是AbstractRefreshableApplicationContext的子类,obtainFreshBeanFactory阶段调用其父类AbstractRefreshableApplicationContext的refreshBeanFactory方法和getBeanFactory。
2 refreshBeanFactory
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Override
protected final void refreshBeanFactory() throws BeansException {
// 检查是否存在BeanFactory
if (hasBeanFactory()) {
// 如果存在则销毁现有的所有bean
destroyBeans();
// 关闭BeanFactory,移除上下文和工厂之间的关系
closeBeanFactory();
}
try {
// 为此上下文创建一个新的内部 Bean 工厂。每次 refresh() 尝试都调用。DefaultListableBeanFactory实例
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置BeanFactory的序列化ID
beanFactory.setSerializationId(getId());
// 对BeanFactory进行一些自定义的配置,如设置是否允许覆盖同名的Bean,是否允许循环依赖等
customizeBeanFactory(beanFactory);
// 加载Bean定义,这是一个模板方法,由具体的子类实现,如XmlWebApplicationContext,AnnotationConfigWebApplicationContext等,
// 根据不同的配置方式,解析XML文件或注解类,将Bean定义封装成BeanDefinition对象,并注册到BeanFactory中
loadBeanDefinitions(beanFactory);
// 将新创建的BeanFactory设置为当前ApplicationContext的BeanFactory
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
// 省略其他代码...
}
2.1 hasBeanFactory
protected final boolean hasBeanFactory() {
// 判断当前上下文bean工厂是否为空
return (this.beanFactory != null);
}
hasBeanFactory判断当前beanFactory 属性是否为空
2.2 destroyBeans
protected void destroyBeans() {
getBeanFactory().destroySingletons();
}
destroyBeans和refresh阶段发生BeansException异常调用销毁bean实例是同一个方法,具体解释看Spring源码-IOC之AbstractApplicationContext#refresh
2.3 closeBeanFactory
@Override
protected final void closeBeanFactory() {
DefaultListableBeanFactory beanFactory = this.beanFactory;
if (beanFactory != null) {
// bean工厂的序列化id置空,同时将bean工厂serializableFactories属性移除key为上下文id的值
beanFactory.setSerializationId(null);
// 将上下文beanFactory属性置空
this.beanFactory = null;
}
}
closeBeanFactory判断如果当前bean工厂不为空,则将其属性serializationId置空,并将上下文的beanFactory属性也置空,相当于取消bean工厂和当前上下文的关联。
2.4 createBeanFactory
protected DefaultListableBeanFactory createBeanFactory() {
// getInternalParentBeanFactory()
// 如果父上下文bean工厂不为空返回该工厂,否则返回父上下文本身
// new DefaultListableBeanFactory
// 忽略给定的接口BeanNameAware、BeanFactoryAware、BeanClassLoaderAware
// 为bean工厂属性instantiationStrategy赋值一个CglibSubclassingInstantiationStrategy,默认使用该对象实例化bean
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
createBeanFactory实例化一个bean工厂并返回,类型为DefaultListableBeanFactory。
@Nullable
protected BeanFactory getInternalParentBeanFactory() {
return (getParent() instanceof ConfigurableApplicationContext cac ?
cac.getBeanFactory() : getParent());
}
@Override
@Nullable
public ApplicationContext getParent() {
return this.parent;
}
调用DefaultListableBeanFactory的构造方法时,还调用了getInternalParentBeanFactory方法,该方法判断当前上下文是否为ConfigurableApplicationContext的子类,如果是则返回其内部bean工厂,否则返回本身。
本案例调用ClassPathXmlApplicationContext构造方法创建ioc容器时,parent没有传值为null,所以getInternalParentBeanFactory方法返回null。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
// 省略其他代码...
}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();
public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}
public AbstractAutowireCapableBeanFactory() {
// 空方法
super();
// 忽略给定的接口BeanNameAware、BeanFactoryAware、BeanClassLoaderAware
// 上下文以其他方式解析依赖项(接口)
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
// 为属性instantiationStrategy赋值一个CglibSubclassingInstantiationStrategy,默认使用该对象实例化bean
this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
}
public void ignoreDependencyInterface(Class<?> ifc) {
this.ignoredDependencyInterfaces.add(ifc);
}
@Override
public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) {
if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) {
throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);
}
if (this == parentBeanFactory) {
throw new IllegalStateException("Cannot set parent bean factory to self");
}
this.parentBeanFactory = parentBeanFactory;
}
// 省略其他代码...
}
DefaultListableBeanFactory的有参构造最终是调用其父类AbstractAutowireCapableBeanFactory 的无参构造方法,该无参构造方法往ignoredDependencyInterfaces属性添加了三种类型的Aware(BeanNameAware、BeanFactoryAware、BeanClassLoaderAware),并为instantiationStrategy 属性赋予一个CglibSubclassingInstantiationStrategy对象,用于实例化bean。
setParentBeanFactory方法用来给父bean工厂属性parentBeanFactory 赋值,本案例此处入参parentBeanFactory为null。
2.5 setSerializationId
public void setSerializationId(@Nullable String serializationId) {
if (serializationId != null) {
// 将当前 BeanFactory 以弱引用的方式存储到 serializableFactories 中,
// 使用传入的 serializationId 作为键
serializableFactories.put(serializationId, new WeakReference<>(this));
}
// 当前BeanFactory本身的序列化ID不为空,则移除
else if (this.serializationId != null) {
serializableFactories.remove(this.serializationId);
}
// 将传入的序列化Id赋值给当前BeanFactory序列化Id
this.serializationId = serializationId;
}
beanFactory.setSerializationId(getId());这段代码将入参serializationId赋值给bean工厂serializationId属性
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
private String id = ObjectUtils.identityToString(this);
@Override
public String getId() {
return this.id;
}
// 省略其他代码...
}
public abstract class ObjectUtils {
public static String identityToString(@Nullable Object obj) {
if (obj == null) {
return EMPTY_STRING;
}
return obj.getClass().getName() + "@" + getIdentityHexString(obj);
}
// 省略其他代码...
}
getId返回当前上下文的唯一id(class对象名称+@+对象哈希码的十六进制),作为bean工厂的序列化id。
2.6 customizeBeanFactory
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
customizeBeanFactory对bean工厂设置是否允许覆盖同名的Bean(allowBeanDefinitionOverriding),是否允许循环依赖(allowCircularReferences)
2.7 loadBeanDefinitions
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
loadBeanDefinitions是一个抽象方法,由子类实现,不同类型上下文读取对应类型的资源配置,从而加载bean定义。ClassPathXmlApplicationContext是AbstractXmlApplicationContext的子类,通过读取xml的配置文件加载,即本案例的beans.xml文件。
AbstractXmlApplicationContext
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为给定的 BeanFactory 创建一个新的 XmlBeanDefinitionReader,并初始化其属性
// XmlBeanDefinitionReader.registry = 当前bean工厂DefaultListableBeanFactory
// XmlBeanDefinitionReader.resourceLoader = 一个新的PathMatchingResourcePatternResolver
// XmlBeanDefinitionReader.environment = 一个新的StandardEnvironment,其父类AbstractEnvironment有初始化一些东西
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 这里对beanDefinitionReader的resourceLoader和environment重新赋值
// 为bean定义加载器添加环境、资源加载器、资源实体解析器
// XmlBeanDefinitionReader.environment = 当前上下文StandardEnvironment
beanDefinitionReader.setEnvironment(this.getEnvironment());
// XmlBeanDefinitionReader.resourceLoader = 当前上下文,示例是ClassPathXmlApplicationContext
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化bean定义加载器,设置是否使用XML验证,默认值为true
// 设置validationMode属性和namespaceAware属性
initBeanDefinitionReader(beanDefinitionReader);
// 加载bean定义
loadBeanDefinitions(beanDefinitionReader);
}
// 省略其他代码...
}
AbstractXmlApplicationContext#loadBeanDefinitions方法中初始化了一个可解析xml的XmlBeanDefinitionReader 。再调用重载方法loadBeanDefinitions加载bean定义。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
// 省略其他代码...
}
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (this.registry instanceof ResourceLoader _resourceLoader) {
this.resourceLoader = _resourceLoader;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
if (this.registry instanceof EnvironmentCapable environmentCapable) {
this.environment = environmentCapable.getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
// 省略其他代码...
}
XmlBeanDefinitionReader 的有参构造方法中,入参registry为bean工厂,方法体调用其父类AbstractBeanDefinitionReader 的无参构造方法,设置registry 、resourceLoader 、environment 相关属性。
案例中,org.springframework.beans.factory.support.AbstractBeanDefinitionReader#AbstractBeanDefinitionReader入参registry为新创建的DefaultListableBeanFactory,非ResourceLoader和EnvironmentCapable 的子类,所以实例化一个PathMatchingResourcePatternResolver赋值给resourceLoader ,新实例化一个StandardEnvironment赋值给environment ,对XmlBeanDefinitionReader 做了初始化。
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 省略其他代码...
beanDefinitionReader.setEnvironment(this.getEnvironment());
// XmlBeanDefinitionReader.resourceLoader = 当前上下文,示例是ClassPathXmlApplicationContext
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 省略其他代码...
}
// 省略其他代码...
}
调完BeanDefinitionReader构造方法,后续调用set方法对相关属性重新赋值,这里的this是当前上下文对象,从ClassPathXmlApplicationContext类继承结构上看,是实现了ResourceLoader接口。
所以当前beanDefinitionReader对象属性中,registry=DefaultListableBeanFactory对象,environment=上下文的environment,resourceLoader=上下文本身,entityResolver=新创建的ResourceEntityResolver对象。
public class ResourceEntityResolver extends DelegatingEntityResolver {
private final ResourceLoader resourceLoader;
public ResourceEntityResolver(ResourceLoader resourceLoader) {
// 调用父类构造方法,
// 包含一个BeansDtdResolver赋值给属性dtdResolver,从 Spring 类路径(或 JAR 文件)加载 DTD,类型都是EntityResolver
// 包含一个PluggableSchemaResolver赋值给属性schemaResolver,使用默认映射文件模式“META-INF/spring.schemas”加载模式 URL,类型都是EntityResolver
super(resourceLoader.getClassLoader());
this.resourceLoader = resourceLoader;
}
// 省略其他代码...
}
public class DelegatingEntityResolver implements EntityResolver {
private final EntityResolver dtdResolver;
private final EntityResolver schemaResolver;
public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
this.dtdResolver = new BeansDtdResolver();
this.schemaResolver = new PluggableSchemaResolver(classLoader);
}
// 省略其他代码...
}
ResourceEntityResolver对象包含当前上下文、BeansDtdResolver、PluggableSchemaResolver。
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
private boolean validating = true;
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 省略其他代码...
initBeanDefinitionReader(beanDefinitionReader);
// 省略其他代码...
}
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
// 设置是否使用XML验证,validating缺省值为true
reader.setValidating(this.validating);
}
// 省略其他代码...
}
initBeanDefinitionReader方法给beanDefinitionReader对象validating属性赋值,缺省值为true。子类也可重写该方法,对XmlBeanDefinitionReader 做定制配置。
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
private boolean validating = true;
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 省略其他代码...
loadBeanDefinitions(beanDefinitionReader);
// 省略其他代码...
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 使用包含class对象构造方法,如new ClassPathXmlApplicationContext("beans.xml", User.class),会从这里解析Resource对象
// 返回ClassPathXmlApplicationContext.configResources属性
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 使用不包含class对象构造方法,如new ClassPathXmlApplicationContext("beans.xml"),会从这里先解析资源路径,转成Resource对象解析
// 返回configLocations.configResources属性
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
// 省略其他代码...
}
XmlBeanDefinitionReader 对象在加载bean定义loadBeanDefinitions方法有两个,解析Resource对象获取String类型的资源路径配置,取决于创建ClassPathXmlApplicationContext时使用哪种构造方法。本案例使用不包含class对象构造方法的方法,走第二部分代码逻辑。实际上第二部分会将String类型的资源配置路径转换成Resource对象,再调用解析Resource的loadBeanDefinitions方法。
XmlBeanDefinitionReader
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
// 省略其他代码...
}
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
@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;
}
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
// 省略其他代码...
}
loadBeanDefinitions调用XmlBeanDefinitionReader 的父类AbstractBeanDefinitionReader方法,抽象类AbstractBeanDefinitionReader 有很多loadBeanDefinitions的重载方法,从源码上看,循环解析资源配置路径。
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
// resourceLoader是当前上下文,实现了ResourcePatternResolver即可解析资源路径
if (resourceLoader instanceof ResourcePatternResolver resourcePatternResolver) {
// Resource pattern matching available.
try {
// 将配置路径转换成Resource,调用ClassPathXmlApplicationContext实例化过程中super(parent)中新建的PathMatchingResourcePatternResolver
Resource[] resources = resourcePatternResolver.getResources(location);
// 加载bean定义
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
// 省略其他代码...
}
将String解析成Resource对象逻辑在public int loadBeanDefinitions(String location, @Nullable Set actualResources)。从初始化XmlBeanDefinitionReader对象的部分,可以知道getResourceLoader方法获取resourceLoader是上下文本身,而当前上下文ClassPathXmlApplicationContext对象是ResourcePatternResolver的子类,if条件通过。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
private final ResourcePatternResolver resourcePatternResolver;
@Override
public Resource[] getResources(String locationPattern) throws IOException {
return this.resourcePatternResolver.getResources(locationPattern);
}
// 省略其他代码...
}
resourcePatternResolver.getResources(location);是当前上下文调用其内部ResourcePatternResolver 对象getResources方法。而ResourcePatternResolver对象则是在ClassPathXmlApplicationContext构造方法中创建的PathMatchingResourcePatternResolver对象。怎么解析的细节就不展开了。本案例中返回的是ClassPathContextResource对象。
所以上下文调用getResources方法,实际上是使用PathMatchingResourcePatternResolver对象的getResources方法。上下文拓展了很多能力,但一般由上下文所持有的的其他实例对象完成。
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
count += loadBeanDefinitions(resource);
}
return count;
}
// 省略其他代码...
}
下一步解析路径配置转换后的Resource对象。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
// 为给定的资源创建一个新的EncodedResource,不指定显式编码或字符集。
return loadBeanDefinitions(new EncodedResource(resource));
}
}
public class EncodedResource implements InputStreamSource {
public EncodedResource(Resource resource) {
this(resource, null, null);
}
private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
super();
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
this.encoding = encoding;
this.charset = charset;
}
// 省略其他代码...
}
解析Resource对象方法有三个实现类,案例中创建的是XmlBeanDefinitionReader对象,调用XmlBeanDefinitionReader#loadBeanDefinitions的时候,实例化了一个EncodedResource对象,持有ClassPathContextResource对象,并未指定encoding 和charset。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
// resourcesCurrentlyBeingLoaded是ThreadLocal,返回一个线程隔离的HashSet
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
// 将资源对象转换成inputStream流
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
// 转码不为空设置转码
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
// 省略其他代码...
}
encodedResource.getResource().getInputStream()中,其Resource对象是ClassPathContextResource,调用其对应的方法将Resource对象转换成InputStream,继续调用doLoadBeanDefinitions方法。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 将流转换成Document对象,com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl
Document doc = doLoadDocument(inputSource, resource);
// 注册bean定义
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
// 省略其他代码...
}
当前doLoadBeanDefinitions方法进一步将inputSource转换成Document对象后,继续调用registerBeanDefinitions方法。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
private Class<? extends BeanDefinitionDocumentReader> documentReaderClass =
DefaultBeanDefinitionDocumentReader.class;
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 通过反射实例化一个org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader对象
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// getRegistry() 返回 当前上下文的bean工厂DefaultListableBeanFactory
// getBeanDefinitionCount()返回加载bean定义之间bean定义数目,这里为0,如果通过其他方式先加载了bean定义则不为0
int countBefore = getRegistry().getBeanDefinitionCount();
// createReaderContext(resource) 创建一个包含使用默认映射路径(META-INF/spring.handlers)的DefaultNamespaceHandlerResolver的XmlReaderContext
// 调用org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
// 属性documentReaderClass=DefaultBeanDefinitionDocumentReader
// 通过反射实例化DefaultBeanDefinitionDocumentReader对象
return BeanUtils.instantiateClass(this.documentReaderClass);
}
// 省略其他代码...
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
@Override
public int getBeanDefinitionCount() {
return this.beanDefinitionMap.size();
}
// 省略其他代码...
}
通过反射创建一个DefaultBeanDefinitionDocumentReader对象,用于解析包含bean定义的Document对象。从上文我们可知XmlBeanDefinitionReader.registry是DefaultListableBeanFactory对象,则getBeanDefinitionCount返回的是bean工厂中bean定义总数,即beanDefinitionMap属性的大小。
案例中bean工厂之前未加载过bean定义,所以beanDefinitionMap大小为0,当前XmlBeanDefinitionReader #registerBeanDefinitions放大的回参int是从Document对象加载bean定义数量。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
@Nullable
private NamespaceHandlerResolver namespaceHandlerResolver;
private ProblemReporter problemReporter = new FailFastProblemReporter();
private ReaderEventListener eventListener = new EmptyReaderEventListener();
private SourceExtractor sourceExtractor = new NullSourceExtractor();
public XmlReaderContext createReaderContext(Resource resource) {
// 属性problemReporter=FailFastProblemReporter实例
// 属性eventListener=EmptyReaderEventListener实例
// 属性sourceExtractor=NullSourceExtractor实例
// getNamespaceHandlerResolver()放回的 缺省值是一个使用默认映射路径(META-INF/spring.handlers)的DefaultNamespaceHandlerResolver,加载NamespaceHandler实现类
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return this.namespaceHandlerResolver;
}
// 省略其他代码...
}
在DefaultBeanDefinitionDocumentReader#registerBeanDefinitions解析之前,入参中调用createReaderContext方法实例化了XmlReaderContext对象,提供对XmlBeanDefinitionReader中配置的NamespaceHandlerResolver的访问。
其中getNamespaceHandlerResolver() 提供处理其它命名空间处理器解析器路径。自动扫描和自动装配的功能也是由这一部分解析出一个NamespaceHandler组件提供。
DefaultBeanDefinitionDocumentReader
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
// doc.getDocumentElement() 这里返回xml的是根节点,用于判断xml是否是spring默认的命名空间,调用不同的节点解析方法
// doc类型是com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
// 实例化BeanDefinitionParserDelegate,为BeanDefinitionParserDelegate.defaults进行初始化
this.delegate = createDelegate(getReaderContext(), root, parent);
// getNamespaceURI(node) 获取所提供节点的命名空间 URI。
// URI为空或者等于http://www.springframework.org/schema/beans,则为默认命名空间
if (this.delegate.isDefaultNamespace(root)) {
// 判断root的属性值是否有包含profile
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// 为环境属性activeProfiles设置spring.profiles.active的关联值,如果为空则为default
// 判断是否包含xml的profile属性值,打印日志
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 空方法 预处理xml
preProcessXml(root);
// 读取bean定义,解析方法
// 分析spring定义的元素调用org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement
// 分析自定义元素调用org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element)
parseBeanDefinitions(root, this.delegate);
// 空方法 后处理xml
postProcessXml(root);
this.delegate = parent;
}
// 省略其他代码...
}
registerBeanDefinitions方法继续调用doRegisterBeanDefinitions方法。
在doRegisterBeanDefinitions方法中,调用createDelegate方法创建了一个BeanDefinitionParserDelegate 对象,并通过该对象判断xml文件中节点是否为"http://www.springframework.org/schema/beans",如果是则判断是否包含profile属性,有profile属性但环境中不存在则直接返回。本案例中没有指定。下一步继续调用preProcessXml、parseBeanDefinitions、postProcessXml。
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
// 实例化一个BeanDefinitionParserDelegate,给其readerContext属性赋值XmlReaderContext
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
// 这里初始化delegate的defaults属性,为加载bean定义使用
// 默认lazyInit为空false
// 默认merge为false
// 默认autowire为no
// autowireCandidates默认为null
// 默认default-init-method默认为null
// 默认default-destroy-method默认为null
// 设置source为null
delegate.initDefaults(root, parentDelegate);
return delegate;
}
// 省略其他代码...
}
public class BeanDefinitionParserDelegate {
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
public static final String PROFILE_ATTRIBUTE = "profile";
private final ReaderEventListener eventListener;
private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
public void initDefaults(Element root, @Nullable BeanDefinitionParserDelegate parent) {
// 为defaults设置默认值
populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
// 发布默认注册事件
// 调用的XmlReaderContext.eventListener(EmptyReaderEventListener)这里是一个空方法
this.readerContext.fireDefaultsRegistered(this.defaults);
}
protected void populateDefaults(DocumentDefaultsDefinition defaults, @Nullable DocumentDefaultsDefinition parentDefaults, Element root) {
// 默认lazyInit为空false
String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
if (isDefaultValue(lazyInit)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to false.
lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
}
defaults.setLazyInit(lazyInit);
// 默认merge为false
String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
if (isDefaultValue(merge)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to false.
merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
}
defaults.setMerge(merge);
// 默认autowire为no
String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
if (isDefaultValue(autowire)) {
// Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
}
defaults.setAutowire(autowire);
// autowireCandidates默认为null,如果default-autowire-candidates和父default-autowire-candidates为空
if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
}
// 默认default-init-method默认为null,如果default-init-method和父default-init-method为空
if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setInitMethod(parentDefaults.getInitMethod());
}
// 默认default-destroy-method默认为null,如果default-destroy-method和父default-destroy-method为空
if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
}
else if (parentDefaults != null) {
defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
}
// 设置source为null
// 最终调用的XmlBeanDefinitionReader.sourceExtractor#extractSource,sourceExtractor对象是NullSourceExtractor,extractSource是一个空方法
defaults.setSource(this.readerContext.extractSource(root));
}
public void fireDefaultsRegistered(DefaultsDefinition defaultsDefinition) {
this.eventListener.defaultsRegistered(defaultsDefinition);
}
public boolean isDefaultNamespace(Node node) {
// getNamespaceURI(node) 获取所提供节点的命名空间 URI。
// URI为空或者等于http://www.springframework.org/schema/beans,则为默认命名空间
return isDefaultNamespace(getNamespaceURI(node));
}
public boolean isDefaultNamespace(@Nullable String namespaceUri) {
return !StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri);
}
// 省略其他代码...
}
先看一下在DefaultBeanDefinitionDocumentReader#createDelegate方法中如何实例化的BeanDefinitionParserDelegate 对象。
调用BeanDefinitionParserDelegate 对象的有参构造,创建一个提供的XmlReaderContext的BeanDefinitionParserDelegate对象。
接着调用BeanDefinitionParserDelegate#initDefaults方法,对其内部对象DocumentDefaultsDefinition的属性进行初始化,如lazyInit、autowire等。最后调用XmlReaderContext的ReaderEventListener发布关于已注册给定默认值的通知。
从上文知道XmlReaderContext所持有的的ReaderEventListener是EmptyReaderEventListener,是个空方法。
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
protected void doRegisterBeanDefinitions(Element root) {
// 省略其他代码...
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析 <bean> 元素
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 如果有适用的命名空间,则通过名称空间处理程序来修饰给定的bean定义。
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 注册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));
}
}
protected void preProcessXml(Element root) {
}
protected void postProcessXml(Element root) {
}
// 省略其他代码...
}
回到DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions方法中,preProcessXml和postProcessXml都是空方法。
parseBeanDefinitions方法判断节点是否为空或者默认命名空间,如果是则调用parseDefaultElement,否则调用BeanDefinitionParserDelegate#parseCustomElement方法。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析import
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// 解析alias
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 解析bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// 解析beans
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
// 递归
doRegisterBeanDefinitions(ele);
}
}
parseDefaultElement分为四个部分,解析import标签、alias标签、bean标签、beans标签
import标签
protected void importBeanDefinitionResource(Element ele) {
// 获取resource元素
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
// Resolve system properties: e.g. "${user.dir}"
// 解析占位符${},获取其关联值
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<>(4);
// Discover whether the location is an absolute or relative URI
// 判断路径是否是相对路径或者绝对路径
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
}
catch (URISyntaxException ex) {
// cannot convert to an URI, considering the location relative
// unless it is the well-known Spring prefix "classpath*:"
}
// Absolute or relative?
// 绝对路径
if (absoluteLocation) {
try {
// 再次调用loadBeanDefinitions接口
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isTraceEnabled()) {
logger.trace("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
}
}
// 相对路径
else {
// No URL -> considering resource location as relative to the current file.
try {
// 根据当前资源创建绝对路径
int importCount;
Resource relativeResource = getReaderContext().getResource().createRelative(location);
// 再次调用loadBeanDefinitions接口
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
// 获取基础路径baseLocation,StringUtils.applyRelativePath(baseLocation, location)拼接完整资源路径
else {
String baseLocation = getReaderContext().getResource().getURL().toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if (logger.isTraceEnabled()) {
logger.trace("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
}
catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from relative location [" + location + "]", ele, ex);
}
}
Resource[] actResArray = actualResources.toArray(new Resource[0]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
解析resource元素中路径为绝对路径或相对路径,重新调用AbstractBeanDefinitionReader#loadBeanDefinitions相关方法解析配置路径。
alias标签
protected void processAliasRegistration(Element ele) {
// 获取name元素
String name = ele.getAttribute(NAME_ATTRIBUTE);
// 获取alias元素
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
boolean valid = true;
if (!StringUtils.hasText(name)) {
getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if (!StringUtils.hasText(alias)) {
getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if (valid) {
try {
// 将别名注册到bean工厂aliasMap中,key为别名,name为bean名称
getReaderContext().getRegistry().registerAlias(name, alias);
}
catch (Exception ex) {
getReaderContext().error("Failed to register alias '" + alias +
"' for bean with name '" + name + "'", ele, ex);
}
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
}
}
获取name和alias元素的值,如果都不为空,则从xmlReaderContext获取bean工厂,调用bean工厂的registerAlias方法。
registerAlias是bean工厂父类SimpleAliasRegistry的方法
public class SimpleAliasRegistry implements AliasRegistry {
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
@Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
synchronized (this.aliasMap) {
// 判断别名是否与bean名称相同
if (alias.equals(name)) {
this.aliasMap.remove(alias);
if (logger.isDebugEnabled()) {
logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
}
else {
// 从aliasMap缓存中获取bean名称
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
// 判断是否允许别名重复覆盖
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
if (logger.isDebugEnabled()) {
logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
registeredName + "' with new target name '" + name + "'");
}
}
// 检查给定的名称是否已经指向另一个方向的给定别名作为别名
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
if (logger.isTraceEnabled()) {
logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}
// 省略其他代码...
}
将别名和bean名称缓存到bean工厂aliasMap中,key为别名,name为bean名称。
bean标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析 <bean> 元素
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 通过名称空间处理程序来修饰给定的bean定义。
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 注册bean定义到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));
}
}
通过BeanDefinitionParserDelegate对象解析节点,转换成包含bean定义的对象BeanDefinitionHolder,再注册到bean工厂中。
delegate.parseBeanDefinitionElement
public class BeanDefinitionParserDelegate {
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 获取id元素
String id = ele.getAttribute(ID_ATTRIBUTE);
// 获取name元素
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
// 如果有name元素,则按指定字符",;"分割成数组,添加到别名
// 如字符串: "Hello, java; Hello world" 指定字符: ",;" 返回数组:[Hello, java, Hello, world]
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 如果没有id,并且别名不为空,则使用别名的第一个值作为bean名称
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
// 验证指定的bean名称和别名是否已经存在,存在则报BeanDefinitionParsingException异常
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 上面的代码主要设置beanName,如果id为空并且设置了name属性,则分割后name后的第一个值作为beanName,否则id作为beanName
// 解析 Bean 定义本身
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 如果bean名称为空,为给定的bean定义生成一个bean名称
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
// 省略其他代码...
}
进入BeanDefinitionParserDelegate#parseBeanDefinitionElement方法,可以看出方法的上半部分主要设置beanName,如果id为空并且设置了name属性,则分割后name后的第一个值作为beanName,否则id作为beanName。
然后调用parseBeanDefinitionElement方法实例化一个AbstractBeanDefinition对象,即是bean定义,入参ele为bean元素,beanName为bean名称,containingBean为null。
最后创建一个包含bean定义,bean名称和别名数组的BeanDefinitionHolder对象。
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 获取class元素
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// 获取parent元素
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 实例化bean定义对象GenericBeanDefinition,设置其属性beanClass
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 将给定 Bean 元素的属性应用于给定的 Bean * 定义,即解析bean元素属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 设置description,用于描述bean,提高代码可读性,极少用到。
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析meta,用于指定bean的元数据。元数据可以包括键值对、注释或其他自定义标记,用于描述bean的特性和行为。
// 涉及类BeanMetadataAttribute
parseMetaElements(ele, bd);
// 解析lookup-method,用于在子类中重写父类的bean方法。当使用Spring的基于配置的AOP时,该标签允许子类通过返回不同的实例来重写父类的方法。
// 涉及类LookupOverride
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析replaced-method,用于在运行时替换bean中的方法。可以通过指定要替换的方法名称和相应的新实现来替换bean中的现有方法。
// 涉及类ReplaceOverride
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析constructor-arg,用于设置构造函数参数的值。当创建bean时,可以通过指定构造函数参数的值来实例化bean对象。可以使用索引或参数名称指定构造函数的参数位置,并将相应的值注入到构造函数中。
// 涉及类ConstructorArgumentValues.ValueHolder
parseConstructorArgElements(ele, bd);
// 解析property,用于设置bean的属性值。它可以用于注入基本类型、引用类型或其他属性。通过指定属性名称和对应的值,可以将值注入到bean的相应属性中。
// 涉及类PropertyValue、BeanMetadataAttribute
parsePropertyElements(ele, bd);
// 解析qualifier,用于标识具有相同类型的多个bean的唯一性。当存在多个同一类型的bean时,可以使用该标签为每个bean设置一个唯一的标识符,以便在注入时进行精确的匹配。
// 涉及类AutowireCandidateQualifier、BeanMetadataAttribute
parseQualifierElements(ele, bd);
// 将配置资源赋值给bean定义
bd.setResource(this.readerContext.getResource());
// 将源赋值给bean定义,如果是ClassPathXmlApplicationContext,则返回空
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
进入解析bean元素的parseBeanDefinitionElement方法,方法中创建AbstractBeanDefinition对象,并一步步解析bean元素中的标签,赋值给AbstractBeanDefinition对象。这里会用到之前初始化的DocumentDefaultsDefinition对象。
delegate.decorateBeanDefinitionIfRequired 其它命名空间
public class BeanDefinitionParserDelegate {
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = originalDef;
// Decorate based on custom attributes first.
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// Decorate based on custom nested elements.
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// 获取命名空间uri
String namespaceUri = getNamespaceURI(node);
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// 获取namespaceUri匹配的命名空间解析器
// getNamespaceHandlerResolver返回DefaultNamespaceHandlerResolver,resolve获取对应解析器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
}
else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
decorateBeanDefinitionIfRequired方法用来解析bean中的其他命名空间的标签。
public class XmlReaderContext extends ReaderContext {
private final NamespaceHandlerResolver namespaceHandlerResolver;
public XmlReaderContext(
Resource resource, ProblemReporter problemReporter,
ReaderEventListener eventListener, SourceExtractor sourceExtractor,
XmlBeanDefinitionReader reader, NamespaceHandlerResolver namespaceHandlerResolver) {
super(resource, problemReporter, eventListener, sourceExtractor);
this.reader = reader;
this.namespaceHandlerResolver = namespaceHandlerResolver;
}
public final NamespaceHandlerResolver getNamespaceHandlerResolver() {
return this.namespaceHandlerResolver;
}
}
readerContext.getNamespaceHandlerResolver()返回本身的namespaceHandlerResolver,而namespaceHandlerResolver是在实例化XmlReaderContext 的时候赋值。
上面也有提到,具体位置在org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions,namespaceHandlerResolver是一个DefaultNamespaceHandlerResolver对象,
this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);调用的是DefaultNamespaceHandlerResolver#resolve方法。
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader, String handlerMappingsLocation) {
Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
this.handlerMappingsLocation = handlerMappingsLocation;
}
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {
this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}
}
实例化DefaultNamespaceHandlerResolver 的时候,加载"META-INF/spring.handlers"路径下的命名空间解析器字典值。
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler namespaceHandler) {
return namespaceHandler;
}
else {
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
DefaultNamespaceHandlerResolver#resolve方法中,通过getHandlerMappings获取所有handlerMappings路径,筛选出符合的命名空间Handler后,使用反射实例化Handler并返回解析对应的标签。
比如在xml文件中使用p命名空间,可以获取对应的handler(SimplePropertyNamespaceHandler)解析p标签。
beans标签
递归调用DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions方法。
3. 总结
- ClassPathXmlApplicationContext在refresh的obtainFreshBeanFactory阶段有完整的实例化bean工厂过程,包含加载bean定义。
- 在加载bean定义的时候,有几个关键类
- XmlBeanDefinitionReader用于读取配置路径,转换成Document对象
- BeanDefinitionDocumentReader用于承载Document对象、XmlReaderContext对象和BeanDefinitionParserDelegate对象,也提供一定的解析xml标签能力。
- BeanDefinitionParserDelegate是用于解析bean标签的类
- XmlReaderContext包含bean工厂和一些实例对象,同时提供其他命名空间解析器。