Spring Bean加载(一)

来源:互联网 发布:宾馆记账软件 编辑:程序博客网 时间:2024/06/04 19:26

前言

当前查看版本Spring 4.3.1.RELEASE,参考《Spring源码深度解析》

Spring加载Bean方式

该图是自己绘制的并不是顺序图!!!只是为了记录当前查看源码到什么位置仅供参考。看不清,可以找我要文件<.-.-.>
源码阅读顺序
这里写图片描述

1、XmlBeanFactory

//过时的/** @deprecated */@Deprecatedpublic class XmlBeanFactory extends DefaultListableBeanFactory {    private final XmlBeanDefinitionReader reader;//主角    public XmlBeanFactory(Resource resource) throws BeansException {        this(resource, (BeanFactory)null);    }    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {        super(parentBeanFactory);        this.reader = new XmlBeanDefinitionReader(this);        this.reader.loadBeanDefinitions(resource);    }}

2、ApplicationContext

ApplicationContext子类
上图是我自己绘制的ApplicationContext类图部分
XmlWebApplicationContext中的loadBeanDefinitions方法

    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";//默认配置文件    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";//配置文件前缀    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";//配置文件后缀    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);        beanDefinitionReader.setEnvironment(this.getEnvironment());        beanDefinitionReader.setResourceLoader(this);        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));        this.initBeanDefinitionReader(beanDefinitionReader);        this.loadBeanDefinitions(beanDefinitionReader);    }    protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {    }    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {        String[] configLocations = this.getConfigLocations();        //调用父类方法获取配置文件路径,没有配置调用getDefaultConfigLocations()方法        if(configLocations != null) {            String[] var3 = configLocations;            int var4 = configLocations.length;            for(int var5 = 0; var5 < var4; ++var5) {                String configLocation = var3[var5];                reader.loadBeanDefinitions(configLocation);            }        }    }    protected String[] getDefaultConfigLocations() {        return this.getNamespace() != null?new String[]{"/WEB-INF/" + this.getNamespace() + ".xml"}:new String[]{"/WEB-INF/applicationContext.xml"};    }

AbstractXmlApplicationContext中的loadBeanDefinitions方法

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory){    //同上面    }    protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {        reader.setValidating(this.validating);    }    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {        Resource[] configResources = this.getConfigResources();        //configResources = null        if(configResources != null) {            reader.loadBeanDefinitions(configResources);        }        String[] configLocations = this.getConfigLocations();        if(configLocations != null) {            reader.loadBeanDefinitions(configLocations);        }    }    protected Resource[] getConfigResources() {        return null;    }

由上面代码可以看出主角是XmlBeanDefinitionReader类下面就开始了解这个类

父类AbstractBeanDefinitionReader类中loadBeanDefinitions重载方法

    //调用子类的loadBeanDefinitions(Resource resource)方法    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {        Assert.notNull(resources, "Resource array must not be null");        int counter = 0;        Resource[] var3 = resources;        int var4 = resources.length;        for(int var5 = 0; var5 < var4; ++var5) {            Resource resource = var3[var5];            counter += this.loadBeanDefinitions((Resource)resource);        }        return counter;    }    //调用下面方法    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {        return this.loadBeanDefinitions(location, (Set)null);    }    //代码那么长主要作用调用子类的loadBeanDefinitions(Resource resource)方法    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {        ResourceLoader resourceLoader = this.getResourceLoader();        if(resourceLoader == null) {            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");        } else {            int loadCount;            if(!(resourceLoader instanceof ResourcePatternResolver)) {                Resource resource = resourceLoader.getResource(location);                loadCount = this.loadBeanDefinitions((Resource)resource);                if(actualResources != null) {                    actualResources.add(resource);                }                if(this.logger.isDebugEnabled()) {                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");                }                return loadCount;            } else {                try {                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);                    loadCount = this.loadBeanDefinitions(resources);                    if(actualResources != null) {                        Resource[] var6 = resources;                        int var7 = resources.length;                        for(int var8 = 0; var8 < var7; ++var8) {                            Resource resource = var6[var8];                            actualResources.add(resource);                        }                    }                    if(this.logger.isDebugEnabled()) {                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");                    }                    return loadCount;                } catch (IOException var10) {                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);                }            }        }    }    //调用本类的loadBeanDefinitions(String location)方法    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {        Assert.notNull(locations, "Location array must not be null");        int counter = 0;        String[] var3 = locations;        int var4 = locations.length;        for(int var5 = 0; var5 < var4; ++var5) {            String location = var3[var5];            counter += this.loadBeanDefinitions(location);//调用第二个方法        }

XmlBeanDefinitionReader中loadBeanDefinitions重载方法

    //作用:将Resource封装成EncodedResour(带编码的Resource)调用下一个方法    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {        return this.loadBeanDefinitions(new EncodedResource(resource));    }    //执行方法    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {        Assert.notNull(encodedResource, "EncodedResource must not be null");        if(this.logger.isInfoEnabled()) {            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());        }        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();        //线程安全 ,但这里 currentResources应该本来就是线程安全的,所以推测不是为了线程安全。应该是为了线程能使用同一个 currentResources        //来源http://blog.csdn.net/ykdsg/article/details/8674947        if(currentResources == null) {            currentResources = new HashSet(4);           this.resourcesCurrentlyBeingLoaded.set(currentResources);        }        if(!((Set)currentResources).add(encodedResource)) {            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");        } else {            int var5;            try {                InputStream inputStream = encodedResource.getResource().getInputStream();                try {                    InputSource inputSource = new InputSource(inputStream);                    if(encodedResource.getEncoding() != null) {                        inputSource.setEncoding(encodedResource.getEncoding());                    }                    //调用doLoadBeanDefinitions方法                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());                } finally {                    inputStream.close();                }            } catch (IOException var15) {                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);            } finally {                ((Set)currentResources).remove(encodedResource);                if(((Set)currentResources).isEmpty()) {                    this.resourcesCurrentlyBeingLoaded.remove();                }            }            return var5;        }    }    //调用下一方法    public int loadBeanDefinitions(InputSource inputSource) throws BeanDefinitionStoreException {        return this.loadBeanDefinitions(inputSource, "resource loaded through SAX InputSource");    }    //调用doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法    public int loadBeanDefinitions(InputSource inputSource, String resourceDescription) throws BeanDefinitionStoreException {        return this.doLoadBeanDefinitions(inputSource, new DescriptiveResource(resourceDescription));    }

以上就是XmlBeanDefinitionReader类的重载方法介绍

下面开始介绍执行方法了

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {        try {            //获取Document对象            Document doc = this.doLoadDocument(inputSource, resource);            //注册Bean            return this.registerBeanDefinitions(doc, resource);        } catch (BeanDefinitionStoreException var4) {            throw var4;        } catch (SAXParseException var5) {            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);        } catch (SAXException var6) {            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);        } catch (ParserConfigurationException var7) {            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);        } catch (IOException var8) {            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);        } catch (Throwable var9) {            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);        }    }    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {        return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware());        //调用下面方法获取验证模式    }    protected int getValidationModeForResource(Resource resource) {        //获取xml文件验证模式XSD或DTD        int validationModeToUse = this.getValidationMode();//1        if(validationModeToUse != 1) {            return validationModeToUse;        } else {            //由代码自动识别判断            int detectedMode = this.detectValidationMode(resource);            return detectedMode != 1?detectedMode:3;        }    }    //调用XmlValidationModeDetector中detectValidationMode方法    protected int detectValidationMode(Resource resource) {        if(resource.isOpen()) {            throw new BeanDefinitionStoreException("Passed-in Resource [" + resource + "] contains an open stream: cannot determine validation mode automatically. Either pass in a Resource that is able to create fresh streams, or explicitly specify the validationMode on your XmlBeanDefinitionReader instance.");        } else {            InputStream inputStream;            try {                inputStream = resource.getInputStream();            } catch (IOException var5) {                throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: cannot open InputStream. Did you attempt to load directly from a SAX InputSource without specifying the validationMode on your XmlBeanDefinitionReader instance?", var5);            }            try {                //调用XmlValidationModeDetector中detectValidationMode方法                return this.validationModeDetector.detectValidationMode(inputStream);            } catch (IOException var4) {                throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: an error occurred whilst reading from the InputStream.", var4);            }        }    }

XmlValidationModeDetector代码节选

    //常量    public static final int VALIDATION_NONE = 0;    public static final int VALIDATION_AUTO = 1;    public static final int VALIDATION_DTD = 2;//DTD校验    public static final int VALIDATION_XSD = 3;//XSD校验    //通过判断是否存在<!--DOCTYPE-->选择DTD或XSD    private static final String DOCTYPE = "DOCTYPE";    private static final String START_COMMENT = "<!--";    private static final String END_COMMENT = "-->";    public int detectValidationMode(InputStream inputStream) throws IOException {        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));        byte var4;        try {            boolean isDtdValidated = false;            while(true) {                String content;                if((content = reader.readLine()) != null) {                    content = this.consumeCommentTokens(content);                    if(this.inComment || !StringUtils.hasText(content)) {                        continue;                    }                    if(this.hasDoctype(content)) {                        //存在DOCTYPE使用DTD校验                        isDtdValidated = true;                    } else if(!this.hasOpeningTag(content)) {                        continue;                    }                }                //对应XSD和DTD常量                int var5 = isDtdValidated?2:3;                return var5;            }        } catch (CharConversionException var9) {            var4 = 1;        } finally {            reader.close();        }        return var4;    }        private boolean hasDoctype(String content) {        return content.contains("DOCTYPE");    }

DefaultDocumentLoader源码节选

    /**     * JAXP attribute used to configure the schema language for validation.     */    private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";    /**     * JAXP attribute value indicating the XSD schema language.     */    private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";    @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);    }    protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)            throws ParserConfigurationException {        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();        factory.setNamespaceAware(namespaceAware);        if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {            factory.setValidating(true);            if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {                // Enforce namespace aware for XSD...                //判断当前是否使用 xml schema 验证                factory.setNamespaceAware(true);                try {                    factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);                }                catch (IllegalArgumentException ex) {                    ParserConfigurationException pcex = new ParserConfigurationException(                            "Unable to validate using XSD: Your JAXP provider [" + factory +                            "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +                            "Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");                    pcex.initCause(ex);                    throw pcex;                }            }        }        return factory;    }

获取完Document对象后开始注册Bean

回到XmlBeanDefinitionReader的doLoadBeanDefinitions方法调用下面的方法

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {    //创建DefaultBeanDefinitionDocumentReader        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();        int countBefore = getRegistry().getBeanDefinitionCount();        //调用DefaultBeanDefinitionDocumentReader中registerBeanDefinitions方法        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));        return getRegistry().getBeanDefinitionCount() - countBefore;    }

DefaultBeanDefinitionDocumentReader源码节选

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {        this.readerContext = readerContext;        logger.debug("Loading bean definitions");        Element root = doc.getDocumentElement();        //核心终于到了        doRegisterBeanDefinitions(root);    }

由于贴太多代码篇幅太长,下篇