点赞的靓仔,你最帅哦!
源码已收录github 查看源码,别忘了star哦!java
初入博客圈,第一个编写的专题定位在设计模式,前面已经完成了部分设计模式的内容,设计模式是框架架构设计的基础,不能说懂设计模式才会懂框架,但懂设计模式必定能够更好的懂框架,而对设计模式深刻了解后,当工做中遇到需求或者问题的时候,甚至可以天然而然的想到用设计模式来解决。git
更重要的是,咱们学习技术是为了提高自我,找到一份好的工做。那么做为面试中的高频题目,很是有必要掌握。本文经过理论 + 实践 + 源码解读的方式来详细的结束委派模式。github
委派模式并不复杂,和其字面含义相似,指委派者接收任务,而后将任务分配给具体作这个任务的对象。就像作项目同样,老板安排任务给项目经理,项目经理再将任务委托给具体作任务的人。面试
这样咋一看和代理模式很是相似,其实能够理解委托模式就是一种特殊的代理模式,他们的区别在于各自关注的点不一样,代理模式一般注重代理的过程,如前置、后置、环绕等功能的加强;而委派模式不注重过程,注重任务的执行结果,就像老板,他不关心项目经理把这件事情安排给谁完成,他关注的是最终的结果。express
委派模式主要涉及到三种角色:委派者、工做者、任务,
如上个图例,委派者即项目经理,工做者即产品、架构师、后端,任务即要作的事情。下面经过代码实现。后端
工做者接口设计模式
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()); } }
测试ide
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完成的,类图结构以下。
//解析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的实现类处理。