那在JDK中体现最明显的,就是JAVA IO方面的一些类,那在JAVA IO中,我们为了增加缓存,我们使用BufferedReader,那现在我们来看一下,那因为增加缓存的功能,类有很多,子类也就需要很多,那现在我们看一下,BufferedReaderpublic class BufferedReader extends Reader看一下,他首先继承了Reader,进来public abstract class Reader implements Readable, Closeable是一个抽象类,接着回来,然后BufferedReader把Reader放到自己的类中,是inprivate Reader in;public BufferedReader(Reader in, int sz) {super(in);if (sz <= 0)throw new IllegalArgumentException("Buffer size <= 0");this.in = in;cb = new char[sz];nextChar = nChars = 0;
}通过Reader来构造BufferedReader,现在我们来类比一下,抽象的煎饼,抽象的装饰者,构造的时候,用抽象的煎饼来构造他,和这里是一致的,正因为在JDK中的JAVA IO,采用了装饰者模式,我们可以无限次的进行装饰转换,转换的目标啊,就是为了得到我们想要的数据类型流对象,class BufferedInputStream extends FilterInputStream 同理BufferedInputStream也是一样的,class BufferedOutputStream extends FilterOutputStream这两个类我们只做一个,首先它继承FilterInputStream,而FilterInputStream又继承FilterInputStream,class FilterInputStream extends InputStream那InputStream是一个抽象类,public abstract class InputStream implements Closeable接着回来,看一下BufferedInputStream他的构造器,这里有两个,随便看一个就可以,public BufferedInputStream(InputStream in) {this(in, DEFAULT_BUFFER_SIZE);
}public BufferedInputStream(InputStream in, int size) {super(in);if (size <= 0) {throw new IllegalArgumentException("Buffer size <= 0");}buf = new byte[size];
}传入的InputStream,是BufferedInputStream父类的父类,我们看一下fill这个方法,在这个fill这个方法中,private void fill() throws IOException {byte[] buffer = getBufIfOpen();if (markpos < 0)pos = 0;            /* no mark: throw away the buffer */else if (pos >= buffer.length)  /* no room left in buffer */if (markpos > 0) {  /* can throw away early part of the buffer */int sz = pos - markpos;System.arraycopy(buffer, markpos, buffer, 0, sz);pos = sz;markpos = 0;} else if (buffer.length >= marklimit) {markpos = -1;   /* buffer got too big, invalidate mark */pos = 0;        /* drop buffer contents */} else if (buffer.length >= MAX_BUFFER_SIZE) {throw new OutOfMemoryError("Required array size too large");} else {            /* grow buffer */int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?pos * 2 : MAX_BUFFER_SIZE;if (nsz > marklimit)nsz = marklimit;byte nbuf[] = new byte[nsz];System.arraycopy(buffer, 0, nbuf, 0, pos);if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {// Can't replace buf if there was an async close.// Note: This would need to be changed if fill()// is ever made accessible to multiple threads.// But for now, the only way CAS can fail is via close.// assert buf == null;throw new IOException("Stream closed");}buffer = nbuf;}count = pos;int n = getInIfOpen().read(buffer, pos, buffer.length - pos);if (n > 0)count = n + pos;
}就实现读取流数据,我们再 看一下FileInputStreamclass FilterInputStream extends InputStream那这里的方法相对简单一些,我们看几个关键的,首先是构造器,传入File,然后装饰成FileInputStream,public FileInputStream(File file) throws FileNotFoundException {String name = (file != null ? file.getPath() : null);SecurityManager security = System.getSecurityManager();if (security != null) {security.checkRead(name);}if (name == null) {throw new NullPointerException();}if (file.isInvalid()) {throw new FileNotFoundException("Invalid file path");}fd = new FileDescriptor();fd.attach(this);path = name;open(name);
}那FileInputStream的父类,我们看一下,InputStream是抽象类,我们现在来看一下他的UML,他有很多子类,这里面有超多的子类,我们看一下FilterInputStream,再打开几个实现,为了更好地对比,这里面打开三个,然后我们看一下FilterInputStream他的子类也有很多,例如刚刚讲的BufferedInputStream,还有DataInputStream,还有很多,比如LineInputStream,那我们可以看到在装饰者模式中,我们的类是非常的多,但是FilterInputStream,是一个装饰者下面都是实际的装饰者,还有一些类我们就不显示到这里了,那Reader和Writer流中

也是一样的,大同小异,我们在使用IO流的时候,因为类的数量比较多,有时候我们也记不住,但是如果我们能够识别出,哪些是抽象被装饰,哪些是实际被装饰者,哪些是抽象装饰者,哪些是实体装饰者,那其实对我们理解来说是非常有益处的,那这些就是装饰者模式在JDK中的应用,那Spring中,你再看一个类,TransactionAwareCacheDecorator,聪明的可以看出来,这个类是处理Spring缓存和同步事务的相关类,那从类里面我们可以看出来,它实现了一个Cache

又组合到这里,我们是不是可以认为他是一个Cache的装饰者,因为这个类名也是非常的明显,然后他的构造器也是非常的明显,把Cache放到入参里面,Spring这个类的主要目的是提供缓存,和Spring事务的同步级别,感兴趣的可以看一下,在Servlet中也大量的使用了装饰者模式,包括我们所讲的单点登录,也对Servlet进行了包装,我们讲过有这么一个类,private final class SessionRepositoryRequestWrapperprivate final class SessionRepositoryRequestWrapperextends HttpServletRequestWrapper {// HttpServletResponse 实例private final HttpServletResponse response;// ServletContext 实例private final ServletContext servletContext;// requestedSession session对象private S requestedSession; // 是否缓存 sessionprivate boolean requestedSessionCached;// sessionIdprivate String requestedSessionId;// sessionId 是否有效private Boolean requestedSessionIdValid;// sessionId 是否失效private boolean requestedSessionInvalidated;// 省略方法
}装饰者模式在Spring Session和Servlet中的使用,首先这个类继承了HttpServletRequestWrapper,我们看一下HttpServletRequestWrapper这个类是Servlet里面的类,Session是Spring Session包下的类,他继承了这个类,然后在构建他自己的时候呢,又把HttpServletRequest传入进来,private SessionRepositoryRequestWrapper(HttpServletRequest request,HttpServletResponse response, ServletContext servletContext) {super(request);this.response = response;this.servletContext = servletContext;
}那他继承了Wrapper,传入的又是ServletRequest,那他两是什么关系呢,public class HttpServletRequestWrapper extends ServletRequestWrapper implementsHttpServletRequestHttpServletRequestWrapper继承ServletRequestWrapper并且实现了HttpServletRequest,这样就很好理解了,也就是说我们继承的HttpServletRequestWrapper这个类,也就实现了HttpServletRequest接口,那在构建他的时候,我们就可以把被装饰的对象,传入进来,然后生成我们自己包装好的类,这里可以看出来,HttpServletRequestWrapper他包装了HttpServletRequest,而SessionRepositoryRequestWrapper呢,又借力打力,他又借着HttpServletRequestWrapper继续包装,我们再看一下HttpServletRequestWrapper这个类,在构造的时候,也是同样的,把要实现的,要装饰的,作为构造的一个入参,同时我们再看一下,在这个类中getSession,我们看一下这个方法,我们可以看到明显是override,明显是覆盖了这个方法,包括获取Servlet上下文,也同理获取getRequestedSessionId,这个HttpServletRequestWrapper实现了HttpServletRequest接口,而HttpServletRequest又继承了SevletRequest接口,继续往上看,SevletRequest他目前是最顶级的,那我们看一下ServletRequest,在他这个层次呢,有没有自己的呢public class ServletRequestWrapper implements ServletRequestServletRequestWrapper他本身也存在自己的Wrapper包装器,注意这里的Requestprivate ServletRequest request;正是父类ServletRequest实现的这个类,构造的时候也是同理public ServletRequestWrapper(ServletRequest request) {if (request == null) {throw new IllegalArgumentException("Request cannot be null");}this.request = request;
}我们看一下UML,因为这里面有很多,包装类和非包装类,我们随便打开几个来看一下,他们的结构,一直到Spring Session的使用当中,首先HttpServletRequest跑不掉,他呢作为一个接口,继承了ServletRequest接口,我们再看一下他下面的HttpServletRequestWrapper,现在还在Servlet中,同时ServletRequest他下面的实现还有一个ServletRequestWrapper,ServletRequestWrapper这里是一个类,HttpServletRequestWrapper这个是一个接口,在这个接口下边继续包装,那继续来看,SessionRepositoryRequestWrapper,这些都是装饰者的使用

因为这里属性比较多,如果打开的话,这个图就不容易看了,我们刚刚在类中所讲的委托对象,记住就可以了,那这里面用的也是通过委托的方式,那这条线是指Request这条线,那在Response中,是一样的,这里说一下,因为装饰者模式,和适配器模式,都可以成为包装器,所以结尾都可能是Wrapper,但是具体的是适配器模式,还是装饰者模式呢,我们还是要看类里面的实现,以及类与类之间的结构,所以我们不能因为是Wrapper就认为是装饰者模式,或者看到Wrapper就是适配器模式,有些地方就把这两个叫做包装模式,或者称Wrapper这个类为包装器,那具体用什么模式呢,我们还要具体看,那在Mybatis当中,是怎么使用装饰者模式的呢,我们看一下Mybatis中Cache这个类,叫这个类名的特别多,我们直接写一下包名,org.apache.ibatis.cache.Cache,我们找到ibatis.cache这个包下的Cache这个类,可以看到这个就是一个接口public interface Cache {String getId();int getSize();void putObject(Object key, Object value);Object getObject(Object key);Object removeObject(Object key);void clear();ReadWriteLock getReadWriteLock();}同时这里有getId,getSize,读写锁,获取他的size,我们看一下这个包在哪里,我们可以看一下他的包叫decorators,更明显了,这些类都是用来装饰Cache的,我们随便看一个,FifoCache先进先出算法package org.apache.ibatis.cache.decorators;public class FifoCache implements Cache 他呢实现Cache这个类,里面看他的命名delegateprivate final Cache delegate;private final LinkedList<Object> keyList;private int size;public FifoCache(Cache delegate) {this.delegate = delegate;this.keyList = new LinkedList<Object>();this.size = 1024;}他这个命名还是非常好的,也就是先进先出这个Cache呢,都是委托给Cache来做的,不过在里面加了自己的实现,比如说这里面的keyList,使用的是LinkedList,同时new一个LinkedList,LinkedList是一个双端队列,还有LruCache,这个你们会比较熟悉/** Lru (first in, first out) cache decorator*/
public class LruCache implements Cache 最近最少使用的装饰者,这个注释写的很明显,而且我在看这段源码的时候,我发现这里面对象的命名,相对容易理解一些,并且注释非常精简,这个也是值得我们学习的地方,那从名字我们来看一下,ScheduledCache这个肯定是调度缓存方面的,SerializedCache还有序列号和反序列化的一些缓存,软引用SoftCache,还有同步缓存SynchronizedCache,还有多线程并发访问,这里可以看一下,里面的方法都是有同步方法修饰的,public class SynchronizedCache implements Cache {private Cache delegate;public SynchronizedCache(Cache delegate) {this.delegate = delegate;}public String getId() {return delegate.getId();}public int getSize() {acquireReadLock();try {return delegate.getSize();} finally {releaseReadLock();}}public void putObject(Object key, Object object) {acquireWriteLock();try {delegate.putObject(key, object);} finally {releaseWriteLock();}}public Object getObject(Object key) {acquireReadLock();try {return delegate.getObject(key);} finally {releaseReadLock();}}public Object removeObject(Object key) {acquireWriteLock();try {return delegate.removeObject(key);} finally {releaseWriteLock();}}public void clear() {acquireWriteLock();try {delegate.clear();} finally {releaseWriteLock();}}public ReadWriteLock getReadWriteLock() {return delegate.getReadWriteLock();}public int hashCode() {return delegate.hashCode();}public boolean equals(Object obj) {return delegate.equals(obj);}private void acquireReadLock() {getReadWriteLock().readLock().lock();}private void releaseReadLock() {getReadWriteLock().readLock().unlock();}private void acquireWriteLock() {getReadWriteLock().writeLock().lock();}private void releaseWriteLock() {getReadWriteLock().writeLock().unlock();}}那这个就更好理解,他只是说,在Cache上一层包装了一下,并且都加了方法,还有一个关于事务的一个Cachepublic class TransactionalCache implements Cache事务性的一个缓存,那有兴趣的非常建议,把Mybatis Cache这些类的源码看一遍,这些都是对Cache的一些装饰,刚刚一起看了JDK的源码,TOMCAT,SpringSession中的,还有Mybatis中的,关于装饰者模式的一个使用,那装饰者模式在源码框架中,应用的如此广泛,包括我们使用的JDK,所以装饰者模式是我们非常值得学习的一个设计模式,希望你们呢能够理解透,巩固好,同时呢,触类旁通,在我们自己的业务中,来抽象出来可以使用装饰者模式的一些业务模型,当然我们不是为了使用设计模式而使用设计模式,一定是使用对应场景的时候,才来使用他

装饰者模式源码解析(spring-session mybatis jdk servlet)相关推荐

  1. 建造者模式源码解析(jdk-guava+mybatis)

    在JDK中是如何使用builder的呢,我们经常使用的一个类一定都用过,StringBuilder这么一个类,public final class StringBuilderextends Abstr ...

  2. Spring源码深度解析(郝佳)-学习-源码解析-Spring整合MyBatis

    了解了MyBatis的单独使用过程之后,我们再来看看它也Spring整合的使用方式,比对之前的示例来找出Spring究竟为我们做了什么操作,哪些操作简化了程序开发. 准备spring71.xml &l ...

  3. Spring源码深度解析(郝佳)-学习-源码解析-Spring MVC(三)-Controller 解析

    在之前的博客中Spring源码深度解析(郝佳)-学习-源码解析-Spring MVC(一),己经对 Spring MVC 的框架做了详细的分析,但是有一个问题,发现举的例子不常用,因为我们在实际开发项 ...

  4. 美团Leaf源码——号段模式源码解析

    前言 分布式ID生成策略基本要求就是全局不重复,最好还能递增,长度较短,性能高,可用性强.关于相关的实现方案有很多,本文着重使用美团开源的分布式ID生成解决方案--Leaf. 关于Leaf,美团官方的 ...

  5. Spark内核(上)——附:两种Yarn模式源码解析

    文章目录 一.Spark内核概述 1.1 Spark核心组件回顾 1.1.1 Driver 1.1.2 Executor 1.2 Spark通用运行流程概述 二.Spark通信架构概述 2.1 Spa ...

  6. 源码解析 - Spring如何实现IoC的?

    点击↑上方↑蓝色"编了个程"关注我~ 每周至少一篇原创文章 这是本公众号的第 28 篇原创文章 荒腔走板 上周一冲动买了个游戏手柄. 小时候很喜欢玩游戏,那个时候手柄游戏还是插卡的 ...

  7. 代理模式源码解析(jdk+spring+mybatis)

    首先是java.lang.reflect,也就是我们刚刚使用的Proxy这个类,这里面coding的时候,也就是debug的时候,这个就是代理的一个典型应用,还有proxyFactoryBean,这个 ...

  8. Spring源码深度解析(郝佳)-学习-源码解析-Spring MVC(一)

    Spring框架提供了构建Web应用程序的全部功能MVC模块,通过策略接口,Spring框架是高度可配置的,而且支持多种视图技术,例如JavaServer Pages(JSP),Velocity,Ti ...

  9. 外观模式源码解析(springjdbc+myabtis+tomcat)

    我们首先看一下外观模式在SpringJDBC中的一些应用,我们看一下JdbcUtils,为了更好理解,把外观模式重新讲了一下,用积分的场景,我们直接继续看源码,这个是spring.jdbc包下的,这个 ...

最新文章

  1. [导入]C#中实现Socket端口复用
  2. 大根堆的删除c语言,二叉堆(一)之 C语言详解
  3. MongoDB工具最新开发 源代码更新 兼 进展报告 - 集群功能开发
  4. html编辑器 br 被div,百度Ueditor编辑器DIV,html标签替换及代码被过滤问题解决方法...
  5. c++性能之对象与指针性能比较、以及java与c++性能对比实测
  6. /usr/bin/ld: cannot find -l*
  7. APUE实战篇1:在Ubuntu环境搭载apue的环境
  8. CodeForces 961G Partitions 题解
  9. ThreadLocal中优雅的数据结构如何体现农夫山泉的广告语
  10. 代码主题darcula_Intellij idea 中的Darcula主题怎么把颜色改回来?
  11. Yii框架zii.widgets.grid自定义按钮
  12. 等额本金计算公式解析
  13. More Effective C++读书笔记
  14. python足球数据可视化_欧洲足球,5大联赛!Python爬虫数据可视化带你解析经典赛事...
  15. ToDesk安装与使用
  16. 友豆火山CPG插件开发001-简介初识
  17. IBM Rational ClearQuest查询使用教程
  18. 全国计算机一级历年选择题,全国计算机一级考试试题MS_Office(历年真题_选择题)...
  19. CF兵种卡强化服务器维护,CF战场模式攻略 兵种卡获取与强化技巧
  20. LINUX下基于LDAP集中系统用户认证系统

热门文章

  1. android 重装sdk或者系统的时模拟器出现can open ****
  2. JAVA去掉HTMl以及CSS样式
  3. android TextView EditTextView一些技巧使用 (视图代码布局)
  4. CentOS 5.5-yum安装配置LNMP
  5. 【Spring学习】Spring JdbcTemplate之五类方法总结
  6. t2 初识Tornado
  7. marin 初学LINUX之路
  8. 关于网络编程的一些问题
  9. Jenkins学习七:Jenkins的授权和访问控制
  10. LVS(MASTER---NAT)