Spring源码解析之路 Bean解析篇

253 阅读2分钟

前言

上一篇写了很多类的名字,还有他们的职责,写他们的目的就是为了能够更好的帮助后期的解读,熟悉一项事物的基本操作就是解构,Spring很大,但是他也是由一个个小的部分组成的,只要熟悉他的组成类,以及他们的职责,那么理解Spring源码就不成问题

加载Bean

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"))

加载bean的入口就是XmlBeanFactory类

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader = new XmlBeanDefinitionReader(this);
        this.reader.loadBeanDefinitions(resource);
    }
    
    

loadBeanDefinitions中实现了Bean的加载

 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Loading XML bean definitions from " + encodedResource);
        }

        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var6;
            try {
                InputStream inputStream = encodedResource.getResource().getInputStream();
                Throwable var4 = null;

                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    // 此方法进行bean加载
                    var6 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                    
                    

在doLoadBeanDefinitions方法进行bean注册

  protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            Document doc = this.doLoadDocument(inputSource, resource);
            int count = this.registerBeanDefinitions(doc, resource);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Loaded " + count + " bean definitions from " + resource);
            }
            

这个方法做了两件事

  • 加载xml文件,得到document
  • 根据返回的Documnt信息注册Bean信息

我们主要关注注册bean的方法registerBeanDefinitions()

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 实例化BeanDefinitionDocumentReader
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        // 执行bean的注册
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

documentReader.registerBeanDefinitions是执行bean注册的方法

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            this.doRegisterBeanDefinitions(doc.getDocumentElement());
        }

doRegisterBeanDefinitions()方法就是最终注册bean的方法

protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
    if (this.delegate.isDefaultNamespace(root)) {
        // 处理profile属性
        String profileSpec = root.getAttribute("profile");
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
            if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                }

                return;
            }
        }
    }
    // 解析前处理 留给子类实现(这个方法里面没有任何内容)
    this.preProcessXml(root);
    this.parseBeanDefinitions(root, this.delegate);
    // 解析后处理 留给子类实现
    this.postProcessXml(root);
    this.delegate = parent;
}

如果解析前后要做处理就可以继承DefaultBeanDefinitionDocumentReader然后重写上面的两个方法就可以了,这里使用的就是模板方法模式 还有的重点是profile 和 解析并注册beanDefinition

  • 这个属性就是可以通过指定不同的环境

  • parseBeanDefinitions方法进行解析并注册beanDefinition

       protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
             // 对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)) {
                             // 对bean的处理
                             this.parseDefaultElement(ele, delegate);
                         } else {
                            // 对bean的处理
                             delegate.parseCustomElement(ele);
                         }
                     }
                 }
             } else {
                 delegate.parseCustomElement(root);
             }
    
         }