设计模式之【委派模式】+ 框架源码分析

点赞的靓仔,你最帅哦!

源码已收录github 查看源码,别忘了star哦!

开题

初入博客圈,第一个编写的专题定位在设计模式,前面已经完成了部分设计模式的内容,设计模式是框架架构设计的基础,不能说懂设计模式才会懂框架,但懂设计模式一定可以更好的懂框架,而对设计模式深入了解后,当工作中遇到需求或者问题的时候,甚至能够自然而然的想到用设计模式来解决。

更重要的是,我们学习技术是为了提升自我,找到一份好的工作。那么作为面试中的高频题目,非常有必要掌握。本文通过理论 + 实践 + 源码解读的方式来详细的结束委派模式。

委派模式

委派模式并不复杂,和其字面含义类似,指委派者接收任务,然后将任务分配给具体做这个任务的对象。就像做项目一样,老板安排任务给项目经理,项目经理再将任务委托给具体做任务的人。

这样咋一看和代理模式非常类似,其实可以理解委托模式就是一种特殊的代理模式,他们的区别在于各自关注的点不同,代理模式通常注重代理的过程,如前置、后置、环绕等功能的增强;而委派模式不注重过程,注重任务的执行结果,就像老板,他不关心项目经理把这件事情安排给谁完成,他关注的是最终的结果。


image

委派模式主要涉及到三种角色:委派者、工作者、任务
如上个图例,委派者即项目经理,工作者即产品、架构师、后端,任务即要做的事情。下面通过代码实现。

工作者接口

package demo.pattren.delegate;

public interface Worker {
    void doJob(Job job);
}

Job定义任务类

package demo.pattren.delegate;

import lombok.Data;
@Data
public class Job {
    //实际开发中的任务类肯定比较复杂,属性非常多
    private String jobName;
}

Worker的其中一个实现,大致类似。其他就省略了,可以在文章开头去我的Github拉取源码。

package demo.pattren.delegate;

/**
 * 开发
 */
public class Development implements Worker {
    @Override
    public void doJob(Job job) {
        System.out.println("开发人员向你抛出异常,项目延期");
        System.out.println("加班加点,开发人员完成工作");
        System.out.println("开发人员黑着眼圈,并完成" + job.getJobName());
    }
}

测试

package demo.pattren.delegate;

import java.util.ArrayList;
import java.util.List;
/**
 * 委派模式模拟测试测试
 */
public class DelegateTest {
    public static void main(String[] args) {
        //任务
        List<Job> project = new ArrayList<>();
        Job job1 = new Job();
        Job job2 = new Job();
        Job job3 = new Job();
        job1.setJobName("原型");
        job2.setJobName("架构");
        job3.setJobName("开发");
        project.add(job1);
        project.add(job2);
        project.add(job3);

        ProjectManager manager = new ProjectManager();
        //产品经理委派任务,对老板来说,任务都交给项目经理,并不关心具体谁完成
        project.forEach(item -> manager.dispatch(item));
    }
}

深入源码解读委派模式

通常写代码的时候,通常会在类名后面加上设计模式的名称,比如JdbcTemplate就用到了模板模式, 委派模式在JDK以及框架中应用非常多,我们用Delegate在Idea中查询,可以查到一大堆,几十上百个不止。


image

我们找一个比较熟悉的BeanDefinitionParserDelegate,查看该类在那些地方有使用。
关于该类的作用翻译如下:

Stateful delegate class used to parse XML bean definitions.

Intended for use by both the main parser and any extension

解析XML配置的委托类,即真正解析XML内容的类。

可以同时用于主解析器以及主解析器的扩展。

如果了解过Spring的容器初始化Bean的过程,那么一定对BeanDefinitionReader不陌生,BeanDefinitionReader是用于读取Bean定义的接口,最终解析配置返回BeanFefinition对象,Debug跟踪源码,在XML定义的Bean的解析最终是交由BeanDefinitionParserDelegate完成的,类图结构如下。


image

XmlBeanDefinitionReader.registerBeanDefinitions

//解析XML并注册为BeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //创建reader
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    //注册解析Bean
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

该方法核心代码是注册解析Bean,继续追踪

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  this.readerContext = readerContext;
  //调用do方法, 
  doRegisterBeanDefinitions(doc.getDocumentElement());
}

以do开头的都是真正干活的方法,继续追踪

protected void doRegisterBeanDefinitions(Element root) {
    //保存当前结点的父委派对象,因为xml是有层级和包含关系,所以处理这里的时候是递归进行的,
    //保证可以正确解析xml到beanDefinition
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    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);
            // We cannot use Profiles.of(...) since profile expressions are not supported
            // in XML config. See SPR-12458 for details.
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                            "] not matching: " + getReaderContext().getResource());
                }
                return;
            }
        }
    }

    preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
}

此时请求执行到了BeanDefinitionParserDelegate,而BeanDefinitionParserDelegate还不是真正解析的类,而是将解析的工作交由解析器处理。我们再将类图关系完善,整个解析处理流程如下。


image

至此,整个处理流程已经清晰。简单总结。

Spring从XML解析到BeanDefinition流程如下。
XmlBeanDefinitionReader为起点,任务交由DefaultBeanDefinitionDocumentReader处理,DefaultBeanDefinitionDocumentReader通过委托类BeanDefinitionParserDelegate将解析任务委托给真正的解析器BeanDefinitionParser的实现类处理。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341