spring源码学习(1)

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

网上有很多spring的源码分析教程,也有很多类图,但是spring的源码特别复杂,一层嵌套一层,刚开始看,很难受,越看越懵,所以我买了本书《spring源码深度解析》。跟着书的内容来学习吧。

首先是spring读取配置文件,spring有一个专门读取配置的较为顶级的接口-Resource。假设我们使用ClassPathResource进行resource的实例化。

    //得到resource的实例
    ClassPathResource resource=new ClassPathResource("beans.xml");

接着,既然有了resource实例,那么就需要分析里面的东西了。我们常用spring的时候,是使用xml的形式(不考虑springBoot),那么对应的工厂应该就是xmlFactory了。

    ClassPathResource resource=new ClassPathResource("beans.xml");
    //这里XmlBeanFactory在4.3.4里面已经过时了
    XmlBeanFactory factory=new XmlBeanFactory(resource);
    //ClassPathXmlApplicationConetext用于比xmlBeanFactory更加强大的功能。
    /*
     *BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
     */
    //由于书上是从xmlBeanFactory开始的,那么我们就用xmlBeanFactory开始分析
    //到xmlBeanFactory的构造函数里。
    public XmlBeanFactory(Resource resource) throws BeansException {
            this(resource, null);
    }
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
            //这里先不管
            super(parentBeanFactory);
            //由方法的名字分析,是为了加载bean吧
            this.reader.loadBeanDefinitions(resource);
    }
    //接着进入loadBeanDefinitions(resource)方法
    @Override
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
            return loadBeanDefinitions(new EncodedResource(resource));//(1)
    }
    //再进去,关键性代码
    //getResource是将(1)中的resource重新得到,可能是resource有编码的要求
    InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            //继续进入
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
        finally {
            inputStream.close();
    }
    //---------------------------------------------------------------------------------------
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
        try {
            //读方法,返回类型,大致猜测一下,应该是说对xml进行解析。返回解析过后的doc
            Document doc = doLoadDocument(inputSource, resource);
            //获取到正确的doc后,应该就是注册并加载bean了吧(重头戏)
            return registerBeanDefinitions(doc, resource);
        }
        //省略了诸多catch语句:解析失败过后的抛错
    }

接下来查看重头戏:注册并加载bean。

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
            //使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader 
            BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
            //读方法名:统计之前的注册次数
            int countBefore = getRegistry().getBeanDefinitionCount();
            //加载并注册bean
            documentReader.registerBeanDefinitions(doc, createReaderContext(resource));//(1)
            return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    //继续进入(1)
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
            this.readerContext = readerContext;
            logger.debug("Loading bean definitions");
            //root:得到节点
            Element root = doc.getDocumentElement();
            //哈哈,应该是核心了吧,真正的加载bean
            doRegisterBeanDefinitions(root);
    }

    protected void doRegisterBeanDefinitions(Element root) {

            BeanDefinitionParserDelegate parent = this.delegate;
            this.delegate = createDelegate(getReaderContext(), root, parent);
            //profile的处理,判断是什么环境:这就达到了不同环境,不同配置文件的效果。
            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)) {
                        if (logger.isInfoEnabled()) {
                            logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                    "] not matching: " + getReaderContext().getResource());
                        }
                        return;
                    }
                }
            }
            //解析前处理:空实现
            preProcessXml(root);
            //还没有注册bean,真的是很深。接着看
            parseBeanDefinitions(root, this.delegate);
            //解析后处理:空实现
            postProcessXml(root);

            this.delegate = parent;
    }
    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;
                        if (delegate.isDefaultNamespace(ele)) {
                            //spring的标签处理bean
                            parseDefaultElement(ele, delegate);
                        }
                        else {
                            //自定义标签:处理bean
                            //这里我现在不想研究,等以后吧,因为目前学习的重点不在于此
                            delegate.parseCustomElement(ele);
                        }
                    }
                }
            }
            else {
                delegate.parseCustomElement(root);
            }
    }

来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring源码学习(1)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏