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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值