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>