spring源码分析---2.Bean加载流程

首先来看下面一段简单的代码

1 BeanFactory bf = new XmlBeanfactory(new ClassPathResource("spring.xml"));
2 bf.getBean("testBean");

这个ClassPathResource类是用于加载classes下的spring配置文件。

我们来看看这个类的继承关系,Resource接口抽象了所有spring内部使用的底层资源,对不同的资源文件都有对应的实现:文件(FileSystemResource),URL资源(UrlResource),InputStream资源(InputStreamResource)等。

 

我们再来看看XmlBeanFactory类的构造方法,this.reader.loadBeanDefinitions(resource)就是资源加载的真正实现,在执行前还调用了下父类的构造方法,我们接下来去看看父类的构造方法。

1 public XmlBeanFactory(Resource resource) throws BeansException {
2         this(resource, null);
3 }
4 public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
5         super(parentBeanFactory);
6         this.reader.loadBeanDefinitions(resource);    //加载资源的真正实现
7 }

首先我们来看看XmlBeanFactory的继承关系,

 

XmlBeanFactory的父类是DefaultListableBeanFactory,DefaultListableBeanFactory的构造方法如下,那我们再来看看DefaultListableBeanFactory的父类AbstractAutowireCapableBeanFactory。

1 public DefaultListableBeanFactory() {
2         super();
3 }

 

AbstractAutowireCapableBeanFactory的构造方法。ignoreDependencyInterface什么作用呢,就是忽略给定接口的自动装配功能。实现了BeanNameAware接口的属性,不会被Spring自动初始化。自动装配时忽略给定的依赖接口,典型应用是通过其他方式解析Application上下文注册依赖,类似于BeanFactory通过BeanFactoryAware进行注入或者ApplicationContext通过ApplicationContextAware进行注入

1 public AbstractAutowireCapableBeanFactory() {
2         super();
3         ignoreDependencyInterface(BeanNameAware.class);
4         ignoreDependencyInterface(BeanFactoryAware.class);
5         ignoreDependencyInterface(BeanClassLoaderAware.class);
6 }

 我们接着来看this.reader.loadBeanDefinitions(resource)方法,doLoadBeanDefinitions(inputSource, encodedResource.getResource())才是核心处理逻辑。

 1 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
 2         Assert.notNull(encodedResource, "EncodedResource must not be null");
 3         if (logger.isInfoEnabled()) {
 4             logger.info("Loading XML bean definitions from " + encodedResource.getResource());
 5         }
 6 
 7         Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
 8         if (currentResources == null) {
 9             currentResources = new HashSet<>(4);
10             this.resourcesCurrentlyBeingLoaded.set(currentResources);
11         }
12         if (!currentResources.add(encodedResource)) {
13             throw new BeanDefinitionStoreException(
14                     "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
15         }
16         try {
17             InputStream inputStream = encodedResource.getResource().getInputStream();
18             try {
19                 InputSource inputSource = new InputSource(inputStream);
20                 if (encodedResource.getEncoding() != null) {  //当设置了编码属性的时候Spring会使用相应的编码作为输入流的编码
21                     inputSource.setEncoding(encodedResource.getEncoding());
22                 }
23                 return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
24             }
25             finally {
26                 inputStream.close();
27             }
28         }
29         catch (IOException ex) {
30             throw new BeanDefinitionStoreException(
31                     "IOException parsing XML document from " + encodedResource.getResource(), ex);
32         }
33         finally {
34             currentResources.remove(encodedResource);
35             if (currentResources.isEmpty()) {
36                 this.resourcesCurrentlyBeingLoaded.remove();
37             }
38         }
39     }

我们来看看doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法,

doLoadDocument(inputSource, resource)这个方法是获取XML文件的验证方式,加载xml文件并得到对应的Document,

registerBeanDefinitions这个方法是通过返回的Document注册Bean信息

 

 1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
 2             throws BeanDefinitionStoreException {
 3         try {
 4             Document doc = doLoadDocument(inputSource, resource);
 5             return registerBeanDefinitions(doc, resource);
 6         }
 7         catch (BeanDefinitionStoreException ex) {
 8             throw ex;
 9         }
10         catch (SAXParseException ex) {
11             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
12                     "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
13         }
14         catch (SAXException ex) {
15             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
16                     "XML document from " + resource + " is invalid", ex);
17         }
18         catch (ParserConfigurationException ex) {
19             throw new BeanDefinitionStoreException(resource.getDescription(),
20                     "Parser configuration exception parsing XML from " + resource, ex);
21         }
22         catch (IOException ex) {
23             throw new BeanDefinitionStoreException(resource.getDescription(),
24                     "IOException parsing XML document from " + resource, ex);
25         }
26         catch (Throwable ex) {
27             throw new BeanDefinitionStoreException(resource.getDescription(),
28                     "Unexpected exception parsing XML document from " + resource, ex);
29         }
30     }

我们主要来看注册bean信息方法吧

1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
2         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
3         int countBefore = getRegistry().getBeanDefinitionCount();
4         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
5         return getRegistry().getBeanDefinitionCount() - countBefore;
6     }
1 @Override
2     public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
3         this.readerContext = readerContext;
4         logger.debug("Loading bean definitions");
5         Element root = doc.getDocumentElement();
6         doRegisterBeanDefinitions(root);
7     }
 1 protected void doRegisterBeanDefinitions(Element root) {
 2         // Any nested <beans> elements will cause recursion in this method. In
 3         // order to propagate and preserve <beans> default-* attributes correctly,
 4         // keep track of the current (parent) delegate, which may be null. Create
 5         // the new (child) delegate with a reference to the parent for fallback purposes,
 6         // then ultimately reset this.delegate back to its original (parent) reference.
 7         // this behavior emulates a stack of delegates without actually necessitating one.
 8         BeanDefinitionParserDelegate parent = this.delegate;  //专门处理解析
 9         this.delegate = createDelegate(getReaderContext(), root, parent);
10 
11         if (this.delegate.isDefaultNamespace(root)) {
12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);  //处理profile属性
13             if (StringUtils.hasText(profileSpec)) {
14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
17                     if (logger.isInfoEnabled()) {
18                         logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
19                                 "] not matching: " + getReaderContext().getResource());
20                     }
21                     return;
22                 }
23             }
24         }
25 
26         preProcessXml(root);
27         parseBeanDefinitions(root, this.delegate);
28         postProcessXml(root);
29 
30         this.delegate = parent;
31     }

解析并注册BeanDefinition

 1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
 2         if (delegate.isDefaultNamespace(root)) {
 3             NodeList nl = root.getChildNodes();
 4             for (int i = 0; i < nl.getLength(); i++) {
 5                 Node node = nl.item(i);
 6                 if (node instanceof Element) {
 7                     Element ele = (Element) node;
 8                     if (delegate.isDefaultNamespace(ele)) {
 9                         parseDefaultElement(ele, delegate);//默认
10                     }
11                     else {
12                         delegate.parseCustomElement(ele);//自定义
13                     }
14                 }
15             }
16         }
17         else {
18             delegate.parseCustomElement(root);//自定义
19         }
20     }

 在Spring的XML配置里面有两大类Bean声明,一个是默认的,如:

1 <bean id="test" class="test.TestBean"/>

另一类就是自定义的,如:

1 <tx:annotation-driven>

 

posted @ 2018-02-20 19:49  Ch1nYK  阅读(312)  评论(0编辑  收藏  举报