关于java:设计模式之委派模式-框架源码分析

点赞的靓仔,你最帅哦!

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

开题

初入博客圈,第一个编写的专题定位在设计模式,后面曾经实现了局部设计模式的内容,设计模式是框架架构设计的根底,不能说懂设计模式才会懂框架,但懂设计模式肯定能够更好的懂框架,而对设计模式深刻理解后,当工作中遇到需要或者问题的时候,甚至可能自然而然的想到用设计模式来解决。

更重要的是,咱们学习技术是为了晋升自我,找到一份好的工作。那么作为面试中的高频题目,十分有必要把握。本文通过实践 + 实际 + 源码解读的形式来具体的完结委派模式。

委派模式

委派模式并不简单,和其字面含意相似,指委派者接管工作,而后将任务分配给具体做这个工作的对象。就像做我的项目一样,老板安顿工作给项目经理,项目经理再将工作委托给具体做工作的人。

这样咋一看和代理模式十分相似,其实能够了解委托模式就是一种非凡的代理模式,他们的区别在于各自关注的点不同,代理模式通常重视代理的过程,如前置、后置、盘绕等性能的加强;而委派模式不重视过程,重视工作的执行后果,就像老板,他不关怀项目经理把这件事件安顿给谁实现,他关注的是最终的后果。

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

工作者接口

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中查问,能够查到一大堆,几十上百个不止。

咱们找一个比拟相熟的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实现的,类图构造如下。

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还不是真正解析的类,而是将解析的工作交由解析器解决。咱们再将类图关系欠缺,整个解析解决流程如下。

至此,整个解决流程曾经清晰。简略总结。

Spring从XML解析到BeanDefinition流程如下。
XmlBeanDefinitionReader为终点,工作交由DefaultBeanDefinitionDocumentReader解决,DefaultBeanDefinitionDocumentReader通过委托类BeanDefinitionParserDelegate将解析工作委托给真正的解析器BeanDefinitionParser的实现类解决。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理