[Spring] BeanFactory parses bean details, beanfactorybean

Source: Internet
Author: User
Tags xml reader

[Spring] BeanFactory parses bean details, beanfactorybean
In this article, we will talk about the BeanFactory bean parsing process in the Spring framework. This article has been published in the original article of the small series. To view the original text, you can click the original text to view it, let's first look at a basic bean definition and use in Spring.

package bean;public class TestBean {    private String beanName = "beanName";    public String getBeanName() {        return beanName;    }    public void setBeanName(String beanName) {        this.beanName = beanName;    }}
The Spring configuration file root. xml is defined as follows:
<?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-4.1.xsd">    <bean id="testBean" class="bean.TestBean"></beans>
The following uses XmlBeanFactory to obtain the bean:
public class BeanTest {    private static final java.util.logging.Logger logger = LoggerFactory.getLogger(BeanTest.class);    @Test    public void getBeanTest() {        BeanFactory factory = new XmlBeanFactory(new ClassPathResource("root.xml"));        TestBean bean = factory.getBean("testBean");        logger.info(bean.getBeanName);    }}
The result of this unit test is to output beanName, which is the most basic bean acquisition operation of Spring. Here, BeanFactory is rarely used as a container to retrieve beans, in enterprise development, ApplicationContext with better functions is generally used. This is not discussed here. The following describes how to use BeanFactory to obtain beans. Now let's analyze the above test code to see what Spring has done for us. The above code completes the functional process almost like this: 1. read the Spring configuration file root. xml; 2. according to root. find the corresponding class configuration for bean configuration in xml and instantiate it. 3. call the output result of the instantiated object. Let's take a look at the XmlBeanFactory source code:
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);   }}
As shown above, XmlBeanFactory inherits DefaultListableBeanFactory. defalistlistablebeanfactory is the default implementation for Spring to register and load beans. It is the core part of bean loading, the difference between XmlBeanFactory and XmlBeanFactory is that XmlBeanFactory uses a custom XML reader XmlBeanDefinitionReader to read its own BeanDefinitionReader. XmlBeanFactory: XmlBeanDefinitionReader is the key to loading beans. Let's take a look at the source code of XmlBeanDefinitionReader (only partial list ):
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {    private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;    private ProblemReporter problemReporter = new FailFastProblemReporter();    private ReaderEventListener eventListener = new EmptyReaderEventListener();    private SourceExtractor sourceExtractor = new NullSourceExtractor();    private NamespaceHandlerResolver namespaceHandlerResolver;    private DocumentLoader documentLoader = new DefaultDocumentLoader();    private EntityResolver entityResolver;    private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger);}
XmlBeanDefinitionReader inherits from AbstractBeanDefinitionReader. The following is the source code of AbstractBeanDefinitionReader (only available ):
public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {    protected final Log logger = LogFactory.getLog(getClass());    private final BeanDefinitionRegistry registry;    private ResourceLoader resourceLoader;    private ClassLoader beanClassLoader;    private Environment environment;    private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();}
XmlBeanDefinitionReader loads the bean in the Spring configuration file in the following three steps: 1. inherit from the methods in AbstractBeanDefinitionReader and use ResourLoader. xml) path to the corresponding Resource file; 2. use DocumentLoader to convert the Resource file to the Ducument file. 3. use the DefaultBeanDefinitionDocumentReader class to parse the Document, and then parse the parsed Element. After understanding the above basics, we will analyze the code in the next example in detail:
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("root.xml"));
Let's take a look at the sequence diagram of XmlBeanFactory initialization below to further understand the execution of this Code, here we can see that the BeanTest test class uses the spring configuration file passed in to the ClassPathResource constructor to construct the instance object of a Resource file, and then constructs the expected XmlBeanFactory instance through this Resource file. We can see from the construction method in the XmlBeanFactory source code above,
public XmlBeanFactory(Resource resource) throws BeansException {     this(resource, null);}public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {     super(parentBeanFactory);     this.reader.loadBeanDefinitions(resource);}
This. reader. loadBeanDefinition (resource) is the real implementation of resource loading. In the sequence diagram, XmlBeanDefinitionReader loads data here. Next, follow up on this. reader. loadBeanDefinition (resource) method,
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {    @Override    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {        return loadBeanDefinitions(new EncodedResource(resource));    }}
In the loadBeanDefinition (resource) method, encode the resource file resource using EncodedResource and pass in the loadBeanDefinitions method. Continue to follow up the loadBeanDefinitions (new EncodedResource (resource) method source code:
Public int loadBeanDefinitions (EncodedResource encodedResource) throws BeanDefinitionStoreException {Assert. notNull (encodedResource, "EncodedResource must not be null"); if (logger. isInfoEnabled () {logger.info ("Loading XML bean definitions from" + encodedResource. getResource ();} // records the loaded resource Set <EncodedResource> currentResources = this. resourcesCurrentlyBeingLoaded. get (); if (currentResour Ces = 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 {// obtain the corresponding InputStream from the resource, which is used to construct InputSource InputStream inputStream = encodedResource. getResource (). getInputStream (); try {InputSource inputSource = new InputSource (inputStream); if (encodedResource. getEncoding ()! = Null) {inputSource. setEncoding (encodedResource. getEncoding ();} // call the doLoadBeanDefinitions method return doLoadBeanDefinitions (inputSource, encodedResource. getResource ();} finally {inputStream. close () ;}} catch (IOException ex) {throw new BeanDefinitionStoreException ("IOException parsing XML document from" + encodedResource. getResource (), ex);} finally {currentResources. remove (encodedResource); if (currentResources. isEmpty () {this. resourcesCurrentlyBeingLoaded. remove ();}}}
Continue to follow up the doLoadBeanDefinitions (inputSource, encodedResource. getResource () method. This is the core method of the bean loading process and bean loading is executed in this method.
Protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {try {Document doc = doLoadDocument (inputSource, resource); return registerBeanDefinitions (doc, resource );} /* omit a bunch of catch */}
Follow up with doLoadDocument (inputSource, resource) source code:
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,            getValidationModeForResource(resource), isNamespaceAware());}
In the doLoadDocument (inputSource, resource) method, the documentLoader mentioned above is used to load the Document. Here DocumentLoader is an interface. What is actually called is its implementation class defadocumentdocumentloader loadDocument method. Follow up with the source code:
public class DefaultDocumentLoader implements DocumentLoader {    @Override    public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);        if (logger.isDebugEnabled()) {            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");        }        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);        return builder.parse(inputSource);    }}
From the source code, we can see that here we first create DocumentBuilderFactory, and then use it to create DocumentBuilder, and then parse inputSource to return the Document Object. After obtaining the Document object, you can register our Bean information. In the above doLoadBeanDefinitions (inputSource, encodedResource. getResource () method, after obtaining the Document object, the following code executes the registerBeanDefinitions (doc, resource) method. See the source code:
Public int registerBeanDefinitions (Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader (); documentReader. setEnvironment (getEnvironment (); // Number of BeanDefinition loads before bean registration int countBefore = getRegistry (). getBeanDefinitionCount (); // load the registered bean documentReader. registerBeanDefinitions (doc, createReaderContext (resource); // The number of BeanDefinition registrations loaded this time return getRegistry (). getBeanDefinitionCount ()-countBefore ;}
The doc here is loaded and converted by the loadDocument method above. It can be seen from the above that the main task is to be implemented by the registerBeanDefinitions () method of BeanDefinitionDocumentReader. Here BeanDefinitionDocumentReader is an interface, the default bean ultbeandefinitiondocumentreader method is used to register the bean function. Follow up its source code:
@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {    this.readerContext = readerContext;    logger.debug("Loading bean definitions");    Element root = doc.getDocumentElement();    doRegisterBeanDefinitions(root);}
Here, after obtaining the Element Object through doc. getDocumentElement () and handing it to the doRegisterBeanDefinitions () method, the XML document is parsed. Follow up the source code of the doRegisterBeanDefinitions () method:
protected void doRegisterBeanDefinitions(Element root) {    BeanDefinitionParserDelegate parent = this.delegate;    this.delegate = createDelegate(getReaderContext(), root, parent);    if (this.delegate.isDefaultNamespace(root)) {        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);    parseBeanDefinitions(root, this.delegate);    postProcessXml(root);    this.delegate = parent;}
The processing process is very clear here. First, we will process the profile, then we will use the parseBeanDefinitions () method to parse the document, and follow up the source code of the parseBeanDefinitions () method:
Protected void parseBeanDefinitions (Element root, BeanDefinitionParserDelegate delegate) {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; // process the bean below if (delegate. isDefaultNamespace (ele) {parseDefaultElement (ele, delegate);} else {delegate. parseCustomElement (ele) ;}}} else {delegate. parseCustomElement (root );}}
In the preceding if-else statement block, parseDefaultElement (ele, delegate) and delegate. parseCustomElement (ele) are used to parse the default namespace and custom namespace in the Spring configuration file. In the XML configuration of Spring, the default Bean declaration is as defined above:
<bean id="testBean" class="bean.TestBean">
The custom Bean declaration is as follows:
<tx:annotation-driven />

The whole process of loading bean in XmlBeanFactory is basically explained here.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.