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

41次阅读

共计 3996 个字符,预计需要花费 10 分钟才能阅读完成。

点赞的靓仔,你最帅哦!

源码已收录 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 的实现类解决。

正文完
 0