spring源码-1- xml的加载与注册

来源:互联网 发布:淘宝千人千面影响 编辑:程序博客网 时间:2024/06/12 18:48
Resource resource = new ClassPathResource("classpath:spring/application.xml");

1.资源加载


ClassPathResource 分析

spring 框架提供bean的加载机制,定义在xml中注入的bean将被创建。通过构造方法    appalication.xml 资源加载 classPathResource -》Resource其它方法 1. getPath 获取路径 2. getClassLoader 获取类加载器 3. exists 资源解析存在性 4. getInputStream 获取输入流 5. getURL 获取url 6. createRelative 创建相对资源路径 7. getDescription 获取clazz 类名 + path 信息
/** *  classpath 下资源加载 */public class ClassPathResource extends AbstractFileResolvingResource {    private final String path;    //jvm 类加载器    private ClassLoader classLoader;    private Class<?> clazz;    public ClassPathResource(String path) {        this(path, (ClassLoader) null);    }    public ClassPathResource(String path, ClassLoader classLoader) {        Assert.notNull(path, "Path must not be null");        //整理classpath 路径 (.. // prefix 等)        String pathToUse = StringUtils.cleanPath(path);        if (pathToUse.startsWith("/")) {            pathToUse = pathToUse.substring(1);        }        this.path = pathToUse;        this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());    }

StringUtils cleanPath(path) 源码解析

clanPath 是对path路径的一个简单处理。
    /**     * 例1 classpath:spring/application.xml     * 例2 http://blog.csdn.net/csdn_ygy     */ public static String cleanPath(String path) {        if (path == null) {            return null;        }        //WINDOWS_FOLDER_SEPARATOR = "\\" FOLDER_SEPARATOR = "/"        /**         *  效果等同于String.replaceAll (使用StringBuffer)         *  用StringBuilder效率更快         */        String pathToUse=replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);        int prefixIndex=pathToUse.indexOf(":");        String prefix="";        if (prefixIndex != -1) {            prefix=pathToUse.substring(0, prefixIndex + 1); //  classpath http            if (prefix.contains("/")) {                prefix="";            } else { // spring/application.xml  /blog.csdn.net/csdn_ygy                pathToUse=pathToUse.substring(prefixIndex + 1);            }        }        if (pathToUse.startsWith(FOLDER_SEPARATOR)) {            prefix=prefix + FOLDER_SEPARATOR;            pathToUse=pathToUse.substring(1); //    spring/application.xml blog.csdn.net/csdn_ygy        }        /**         *  以/ 切割   String用正则且步骤繁琐,         *  本方法采用Stringbuilder 效率较快 {"spring","application.xml"}         */        String[] pathArray=delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);        List<String> pathElements=new LinkedList<>();        int tops=0;        for (int i=pathArray.length - 1; i >= 0; i--) {            String element=pathArray[i];    //application.xml            if (CURRENT_PATH.equals(element)) {            } else if (TOP_PATH.equals(element)) {                tops++;            } else {                if (tops > 0) {                    // Merging path element with element corresponding to top path.                    tops--;                } else {                    // Normal path element found.                    pathElements.add(0, element);                }            }        }        // Remaining top paths need to be retained.        for (int i=0; i < tops; i++) {            pathElements.add(0, TOP_PATH);        }        return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);    }

2.资源解析


XmlBeanFactory (已过时)
直接使用DefaultListableBeanFactory (主要是对bean 注册后的处理)以及XmlBeanDefinitionReader (资源文件读取 解析 及注册)

// 用于从xml中读取 beanDefinition@Deprecated@SuppressWarnings({"serial", "all"})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);        //加载beanDefinition        this.reader.loadBeanDefinitions(resource);    }}

2.1资源解析-xml验证

XmlValidationModeDetector 源码分析(获取xml 后 ,对xml 约束文件解读 ,进行验证)

// 1 auto  2 dtd 3 xsd(schema) : xml 验证模式 public int detectValidationMode(InputStream inputStream) throws IOException {        // Peek into the file to look for DOCTYPE.        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));        try {            boolean isDtdValidated = false;  //是否是dtd            String content;            while ((content = reader.readLine()) != null) {                // 判断是否为注释    <-- 注释设置 true  "<-- xxxxxxxx" => xxxxxxxxxxxxx                content = consumeCommentTokens(content);                //如果读取的是注释 或者空则跳过                if (this.inComment || !StringUtils.hasText(content)) {                    continue;                }                if (hasDoctype(content)) {  //dtd 标志                    isDtdValidated = true;                    break;                }                if (hasOpeningTag(content)) {  //是否含有 <                    // End of meaningful data...                    break;                }            }            return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD); //dtd 或者xsd(schema)         }        catch (CharConversionException ex) {            // Choked on some character encoding...            // Leave the decision up to the caller.            return VALIDATION_AUTO;  //采取自动        }        finally {            reader.close();  //关闭资源        }    }

2.2资源解析-解析为document

DefaultDocumentLoader源码分析

//xml -》 document -》 bean    @Override  // 资源  对象解析器 错误处理器  xml验证  xml命名空间         //由resourceLoader =》 获取public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,             ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {        // 命名空间 和 验证模式(dtd xsd) -》 DocumentBuilderFactory        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);    }

2.3资源解析-beandefinition 注册

XmlBeanDefinitionReader 分析(资源文件读取 解析 及注册)

** * 资源文件读取 解析 及注册 */public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {    //1.从xml中加载 beandefinition 返回注册的beandefinition 数量    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());        }        //通过属性记录已经加载过的资源        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();        if (currentResources == null) {            currentResources = new HashSet<>(4);            this.resourcesCurrentlyBeingLoaded.set(currentResources);        }        if (!currentResources.add(encodedResource)) {            throw new BeanDefinitionStoreException(                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");        }        try {            //获取资源输入流            InputStream inputStream = encodedResource.getResource().getInputStream();            try {                InputSource inputSource = new InputSource(inputStream);                if (encodedResource.getEncoding() != null) {                    inputSource.setEncoding(encodedResource.getEncoding());                }                //1.DocumentLoader 转化、解析document                //2.新建 BeanDefinitionDocumentReader (//定义读取document  并注册beandefinition功能)                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();            }        }    }}//注册beandefinition 个数public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();        int countBefore = getRegistry().getBeanDefinitionCount();  //已加载bean 个数        //加载及注册bean        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));        //此次注册个数        return getRegistry().getBeanDefinitionCount() - countBefore;      }
0 0