BeanFactory与ApplicationContext区别
BeanFactory是ApplicationContext的一个子集,BeanFactory只提供简单容器的功能,就像只有一个水桶,水桶里面只装了水。(水桶就像beanFactory,水就是bean)。ApplicationContext除了有容器功能以外,还提供了国际化,事件监听等,就像水桶了除了装了水,还有鱼,虾。
Spring Bean加载过程
言归正传,看bean的加载过程。我们只要选一个BeanFactory(单纯的水桶)作为例子来讲解,来看看水桶是怎么一步一步装水的。
测试代码:
/**
* <pre>类名: ApplicationContextTest</pre>
* <pre>描述: 应用上下文测试</pre>
* <pre>版权: web_chen@163.com</pre>
* <pre>日期: 2020/10/15 9:16</pre>
* <pre>作者: chenwb</pre>
*/
public class ApplicationContextTest {
public static void main(String[] args) {
XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("/XmlConfig.xml"));
System.out.println(((User)xmlBeanFactory.getBean("user")).getName());
}
}
XmlConfig.xml,就是一个简单的user Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="ioc.User">
<property name="name" value="Jerry"/>
</bean>
</beans>
执行结果就是打印一次Jerry
十月 15, 2020 9:33:54 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [XmlConfig.xml]
Jerry
进入XmlBeanFactory:
它继承了DefaultListableBeanFactory,这是一个最常见的bean工厂实现。XmlBeanFactory内容很少,只有一个专门针对XML配置读取的XmlBeanDefinitionReader,XmlBeanDefinitionReader负责读取XML的Bean定义。
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
在DefaultListableBeanFactory中,主要有一个ConcurrentHashMap用来beanDefinition的定义(因为我们这次只管Bean的加载,就只管beanDefinition吧):
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
我们开始载入bean,XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource):
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
// 进行BeanDefinitions载入
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// resourcesCurrentlyBeingLoaded是一个ThreadLocal,用来记录当前正在载入的资源(主要是为并发场景考虑的,但我们这里没有并发)
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
// 并发场景重复载入资源时报错
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 将encodedResource转为InputStream,再转为InputSource
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 真正开始加载bean定义
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
// threadLocal用完之后移除
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
// 前面资源格式进行了转换,接下来进行“真家伙”了
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 加载Document
Document doc = doLoadDocument(inputSource, resource);
// 根据Document注册Bean
return registerBeanDefinitions(doc, resource);
}
...省略异常捕获
}
接下来就是doLoadDocument与registerBeanDefinitions了,就是一个取水,并将水加入水桶一样:
先看doLoadDocument,默认使用的是DefaultDocumentLoader:
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
/**
* Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
* XML parser.
*/
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
// 创建构建工厂
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
// 获取构造器
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
// 生成Document
return builder.parse(inputSource);
}
再看registerBeanDefinitions:
// 返回的是本次注册的bean定义数量
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// BeanDefinitionDocumentReader 采用的是DefaultBeanDefinitionDocumentReader,不过这里采用的是反射,见下面
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
// 根据documentReader读取BeanDefinitions; 后面会讲createReaderContext(resource)
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
// 通过反射实现,使用的Reader是可以进行自定义配置的
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
进入DefaultBeanDefinitionDocumentReader.registerBeanDefinitions:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
// 获取Document的根节点
Element root = doc.getDocumentElement();
// 从根节点进行加载
doRegisterBeanDefinitions(root);
}
```java
protected void doRegisterBeanDefinitions(Element root) {
// bean定义解析委托给BeanDefinitionParserDelegate
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
// 读取profile属性,根据profile进行bean的注册,不符合profile的bean就不进行注册
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)) {
return;
}
}
}
// 解析前
preProcessXml(root);
// 开始解析BeanDefinitions
parseBeanDefinitions(root, this.delegate);
// 解析后
postProcessXml(root);
this.delegate = parent;
}
前面已经获取了Document、根据Profile选取要加载的Beans,并将解析的工作委托给DefaultBeanDefinitionDocumentReader,接下来看DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)对每个Element进行解析:
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
* @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 如果是默认的命名空间http://www.springframework.org/schema/beans
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);
}
}
}
}
// 否则根据自定义的XSD进行自定义节点的解析
else {
delegate.parseCustomElement(root);
}
}
// 校验默认的节点名称
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);
}
}
前面我们水桶有了beanDefinitionMap,水也取到了parseBeanDefinitions,那后来水是如何放入水桶的呢?:
那就是在上面提到的processBeanDefinition方法了:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析BeanDefinition,并交给BeanDefinitionHolder 持有。
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 添加bean的其他属性,如scope,lazy-init等
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 将bean注册进工厂 ,看下面
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
// BeanDefinitionReaderUtils.registerBeanDefinition
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 获取beanName,通过注册器BeanDefinitionRegistry 将bean注入到工厂中。这个注册器是XmlBeanDefinitionReader提供的
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
......
}
上面提到的注册器是XmlBeanDefinitionReader提供的,如果你还记得,一开始的XmlBeanFactory定义的就是这个XmlBeanDefinitionReader(this),并将DefaultListableBeanFactory实现的BeanDefinitionRegistry注入到XmlBeanDefinitionReader中。而在registerBeanDefinitions(Document doc, Resource resource)中,createReaderContext方法又将XmlBeanDefinitionReader传递下去,使解析的时候可以通过getReaderContext().getRegistry()获取到一开始在DefaultListableBeanFactory实现的BeanDefinitionRegistry。
而registerBeanDefinition又是DefaultListableBeanFactory实现的
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
BeanDefinition oldBeanDefinition;
synchronized (this.beanDefinitionMap) {
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//......校验
}
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
// 将beanDefinition加入到beanDefinitionMap中
this.beanDefinitionMap.put(beanName, beanDefinition);
}
}
总结:
这是一个拿桶,取水,装水的过程。先看整体,再仔细看细节。