当前位置: 首页 > news >正文

网站排名云优化工具网站建设运营公众号运营合同

网站排名云优化工具,网站建设运营公众号运营合同,中国最火的网站,珠海建设网站的公司简介转载自 Mybatis 使用的 9 种设计模式#xff0c;真是太有用了 虽然我们都知道有26个设计模式#xff0c;但是大多停留在概念层面#xff0c;真实开发中很少遇到#xff0c;Mybatis源码中使用了大量的设计模式#xff0c;阅读源码并观察设计模式在其中的应用#xff0c;…转载自  Mybatis 使用的 9 种设计模式真是太有用了 虽然我们都知道有26个设计模式但是大多停留在概念层面真实开发中很少遇到Mybatis源码中使用了大量的设计模式阅读源码并观察设计模式在其中的应用能够更深入的理解设计模式。 Mybatis至少遇到了以下的设计模式的使用 Builder模式例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder 工厂模式例如SqlSessionFactory、ObjectFactory、MapperProxyFactory 单例模式例如ErrorContext和LogFactory 代理模式Mybatis实现的核心比如MapperProxy、ConnectionLogger用的jdk的动态代理还有executor.loader包使用了cglib或者javassist达到延迟加载的效果 组合模式例如SqlNode和各个子类ChooseSqlNode等 模板方法模式例如BaseExecutor和SimpleExecutor还有BaseTypeHandler和所有的子类例如IntegerTypeHandler 适配器模式例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现 装饰者模式例如Cache包中的cache.decorators子包中等各个装饰者的实现 迭代器模式例如迭代器模式PropertyTokenizer 接下来挨个模式进行解读先介绍模式自身的知识然后解读在Mybatis中怎样应用了该模式。  1、Builder模式 Builder模式的定义是“将一个复杂对象的构建与它的表示分离使得同样的构建过程可以创建不同的表示。”它属于创建类模式一般来说如果一个对象的构建比较复杂超出了构造函数所能包含的范围就可以使用工厂模式和Builder模式相对于工厂模式会产出一个完整的产品Builder应用于更加复杂的对象的构建甚至只会构建产品的一个部分。 在Mybatis环境的初始化过程中SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的MybatisMapConfig.xml和所有的*Mapper.xml文件构建Mybatis运行的核心对象Configuration对象然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。 其中XMLConfigBuilder在构建Configuration对象时也会调用XMLMapperBuilder用于读取*Mapper文件而XMLMapperBuilder会使用XMLStatementBuilder来读取和build所有的SQL语句。 在这个过程中有一个相似的特点就是这些Builder会读取文件或者配置然后做大量的XpathParser解析、配置或语法的解析、反射生成对象、存入结果缓存等步骤这么多的工作都不是一个构造函数所能包括的因此大量采用了Builder模式来解决。 对于builder的具体类方法都大都用build*开头比如SqlSessionFactoryBuilder为例它包含以下方法 即根据不同的输入参数来构建SqlSessionFactory这个工厂对象。 2、工厂模式 在Mybatis中比如SqlSessionFactory使用的是工厂模式该工厂没有那么复杂的逻辑是一个简单工厂模式。 简单工厂模式(Simple Factory Pattern)又称为静态工厂方法(Static Factory Method)模式它属于类创建型模式。在简单工厂模式中可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例被创建的实例通常都具有共同的父类。 SqlSession可以认为是一个Mybatis工作的核心的接口通过这个接口可以执行执行SQL语句、获取Mappers、管理事务。类似于连接MySQL的Connection对象。从 0 开始手写一个 Mybatis 框架这个我推荐你看下。 可以看到该Factory的openSession方法重载了很多个分别支持autoCommit、Executor、Transaction等参数的输入来构建核心的SqlSession对象。 在DefaultSqlSessionFactory的默认工厂实现里有一个方法可以看出工厂怎么产出一个产品   private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,boolean autoCommit) {Transaction tx  null;try {final Environment environment configuration.getEnvironment();final TransactionFactory transactionFactory getTransactionFactoryFromEnvironment(environment);tx transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);final Executor executor configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call// close()throw ExceptionFactory.wrapException(Error opening session.  Cause:   e, e);} finally {ErrorContext.instance().reset();}} 这是一个openSession调用的底层方法该方法先从configuration读取对应的环境配置然后初始化TransactionFactory获得一个Transaction对象然后通过Transaction获取一个Executor对象最后通过configuration、Executor、是否autoCommit三个参数构建了SqlSession。 在这里其实也可以看到端倪SqlSession的执行其实是委托给对应的Executor来进行的。 而对于LogFactory它的实现代码   public final class LogFactory {private static Constructor? extends Log logConstructor;private LogFactory() {// disable construction}public static Log getLog(Class? aClass) {return getLog(aClass.getName());} 这里有个特别的地方是Log变量的的类型是Constructor? extends Log也就是说该工厂生产的不只是一个产品而是具有Log公共接口的一系列产品比如Log4jImpl、Slf4jImpl等很多具体的Log。 3、单例模式 单例模式(Singleton Pattern)单例模式确保某一个类只有一个实例而且自行实例化并向整个系统提供这个实例这个类称为单例类它提供全局访问的方法。 单例模式的要点有三个一是某个类只能有一个实例二是它必须自行创建这个实例三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。单例模式又名单件模式或单态模式。 在Mybatis中有两个地方用到单例模式ErrorContext和LogFactory其中ErrorContext是用在每个线程范围内的单例用于记录该线程的执行环境错误信息而LogFactory则是提供给整个Mybatis使用的日志工厂用于获得针对项目配置好的日志对象。设计模式之单例模式实践这篇文章推荐你看下。 ErrorContext的单例实现代码 public class ErrorContext {private static final ThreadLocalErrorContext LOCAL  new ThreadLocalErrorContext();private ErrorContext() {}public static ErrorContext instance() {ErrorContext context LOCAL.get();if (context  null) {context  new ErrorContext();LOCAL.set(context);}return context;} 构造函数是private修饰具有一个static的局部instance变量和一个获取instance变量的方法在获取实例的方法中先判断是否为空如果是的话就先创建然后返回构造好的对象。 只是这里有个有趣的地方是LOCAL的静态实例变量使用了ThreadLocal修饰也就是说它属于每个线程各自的数据而在instance()方法中先获取本线程的该实例如果没有就创建该线程独有的ErrorContext。 4、代理模式 代理模式可以认为是Mybatis的核心使用的模式正是由于这个模式我们只需要编写Mapper.java接口不需要实现由Mybatis后台帮我们完成具体SQL的执行。 代理模式(Proxy Pattern) 给某一个对象提供一个代 理并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate它是一种对象结构型模式。 代理模式包含如下角色 Subject: 抽象主题角色 Proxy: 代理主题角色 RealSubject: 真实主题角色 这里有两个步骤第一个是提前创建一个Proxy第二个是使用的时候会自动请求Proxy然后由Proxy来执行具体事务 当我们使用Configuration的getMapper方法时会调用mapperRegistry.getMapper方法而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理 /** * author Lasse Voss */ public class MapperProxyFactoryT {private final ClassT mapperInterface;private final MapMethod, MapperMethod methodCache  new ConcurrentHashMapMethod, MapperMethod();public MapperProxyFactory(ClassT mapperInterface) {this.mapperInterface mapperInterface;}public ClassT getMapperInterface() {return mapperInterface;}public MapMethod, MapperMethod getMethodCache() {return methodCache;}SuppressWarnings(unchecked)protected T newInstance(MapperProxyT mapperProxy) {return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface },mapperProxy);}public T newInstance(SqlSession sqlSession) {final MapperProxyT mapperProxy  new MapperProxyT(sqlSession, mapperInterface, methodCache);return newInstance(mapperProxy);}} 在这里先通过T newInstance(SqlSession sqlSession)方法会得到一个MapperProxy对象然后调用T newInstance(MapperProxyT mapperProxy)生成代理对象然后返回。 而查看MapperProxy的代码可以看到如下内容 public class MapperProxyT implements InvocationHandler, Serializable {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else if (isDefaultMethod(method)) {return invokeDefaultMethod(proxy, method, args);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}final MapperMethod mapperMethod cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);} 非常典型的该MapperProxy类实现了InvocationHandler接口并且实现了该接口的invoke方法。 通过这种方式我们只需要编写Mapper.java接口类当真正执行一个Mapper接口的时候就会转发给MapperProxy.invoke方法而该方法则会调用后续的sqlSession.cudexecutor.executeprepareStatement等一系列方法完成SQL的执行和返回。 5、组合模式 组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。 组合模式对单个对象(叶子对象)和组合对象(组合对象)具有一致性它将对象组织到树结构中可以用来描述整体与部分的关系。同时它也模糊了简单元素(叶子对象)和复杂元素(容器对象)的概念使得客户能够像处理简单元素一样来处理复杂元素从而使客户程序能够与复杂元素的内部结构解耦。 在使用组合模式中需要注意一点也是组合模式最关键的地方叶子对象和组合对象实现相同的接口。这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。 Mybatis支持动态SQL的强大功能比如下面的这个SQL update idupdate parameterTypeorg.format.dynamicproxy.mybatis.bean.UserUPDATE userstrim prefixSET prefixOverrides,if testname ! null and name ! name  #{name}/ifif testage ! null and age ! , age  #{age}/ifif testbirthday ! null and birthday ! , birthday  #{birthday}/if/trimwhere id  ${id} /update 在这里面使用到了trim、if等动态元素可以根据条件来生成不同情况下的SQL 在DynamicSqlSource.getBoundSql方法里调用了rootSqlNode.apply(context)方法apply方法是所有的动态节点都实现的接口 public interface SqlNode {boolean apply(DynamicContext context); } 对于实现该SqlSource接口的所有节点就是整个组合模式树的各个节点 组合模式的简单之处在于所有的子节点都是同一类节点可以递归的向下执行比如对于TextSqlNode因为它是最底层的叶子节点所以直接将对应的内容append到SQL语句中 Overridepublic boolean apply(DynamicContext context) {GenericTokenParser parser createParser(new BindingTokenParser(context, injectionFilter));context.appendSql(parser.parse(text));return true;} 但是对于IfSqlNode就需要先做判断如果判断通过仍然会调用子元素的SqlNode即contents.apply方法实现递归的解析。 Overridepublic boolean apply(DynamicContext context) {if (evaluator.evaluateBoolean(test, context.getBindings())) {contents.apply(context);return true;}return false;} 6、模板方法模式 模板方法模式是所有模式中最为常见的几个模式之一是基于继承的代码复用的基本技术。关注Java技术栈微信公众号在后台回复关键字架构可以获取更多栈长整理的架构和设计模式干货。 模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架另一些设计师则负责给出这个算法的各个逻辑步骤。代表这些具体逻辑步骤的方法称做基本方法(primitive method)而将这些基本方法汇总起来的方法叫做模板方法(template method)这个设计模式的名字就是从此而来。 模板类定义一个操作中的算法的骨架而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 在Mybatis中sqlSession的SQL执行都是委托给Executor实现的Executor包含以下结构 其中的BaseExecutor就采用了模板方法模式它实现了大部分的SQL执行逻辑然后把以下几个方法交给子类定制化完成 protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;protected abstract ListBatchResult doFlushStatements(boolean isRollback) throws SQLException;protected abstract E ListE doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,ResultHandler resultHandler, BoundSql boundSql) throws SQLException; 该模板方法类有几个子类的具体实现使用了不同的策略 简单SimpleExecutor每执行一次update或select就开启一个Statement对象用完立刻关闭Statement对象。可以是Statement或PrepareStatement对象 重用ReuseExecutor执行update或select以sql作为key查找Statement对象存在就使用不存在就创建用完后不关闭Statement对象而是放置于MapString, Statement内供下一次使用。可以是Statement或PrepareStatement对象 批量BatchExecutor执行update没有selectJDBC批处理不支持select将所有sql都添加到批处理中addBatch()等待统一执行executeBatch()它缓存了多个Statement对象每个Statement对象都是addBatch()完毕后等待逐一执行executeBatch()批处理的BatchExecutor相当于维护了多个桶每个桶里都装了很多属于自己的SQL就像苹果蓝里装了很多苹果番茄蓝里装了很多番茄最后再统一倒进仓库。可以是Statement或PrepareStatement对象 比如在SimpleExecutor中这样实现update方法 Override public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {Statement stmt  null;try {Configuration configuration ms.getConfiguration();StatementHandler handler configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null,null);stmt prepareStatement(handler, ms.getStatementLog());return handler.update(stmt);} finally {closeStatement(stmt);}} 7、适配器模式 适配器模式(Adapter Pattern) 将一个接口转换成客户希望的另一个接口适配器模式使接口不兼容的那些类可以一起工作其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式也可以作为对象结构型模式。 在Mybatsi的logging包中有一个Log接口 /** * author Clinton Begin */ public interface Log {boolean isDebugEnabled();boolean isTraceEnabled();void error(String s, Throwable e);void error(String s);void debug(String s);void trace(String s);void warn(String s);} 该接口定义了Mybatis直接使用的日志方法而Log接口具体由谁来实现呢Mybatis提供了多种日志框架的实现这些实现都匹配这个Log接口所定义的接口方法最终实现了所有外部日志框架到Mybatis日志包的适配 比如对于Log4jImpl的实现来说该实现持有了org.apache.log4j.Logger的实例然后所有的日志方法均委托该实例来实现。 public class Log4jImpl implements Log {private static final String FQCN Log4jImpl.class.getName();private Logger log;public Log4jImpl(String clazz) {log Logger.getLogger(clazz);}Overridepublic boolean isDebugEnabled() {return log.isDebugEnabled();}Overridepublic boolean isTraceEnabled() {return log.isTraceEnabled();}Overridepublic void error(String s, Throwable e) {log.log(FQCN, Level.ERROR, s, e);}Overridepublic void error(String s) {log.log(FQCN, Level.ERROR, s, null);}Overridepublic void debug(String s) {log.log(FQCN, Level.DEBUG, s, null);}Overridepublic void trace(String s) {log.log(FQCN, Level.TRACE, s, null);}Overridepublic void warn(String s) {log.log(FQCN, Level.WARN, s, null);}} 8、装饰者模式 装饰模式(Decorator Pattern) 动态地给一个对象增加一些额外的职责(Responsibility)就增加对象功能来说装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper)与适配器模式的别名相同但它们适用于不同的场合。根据翻译的不同装饰模式也有人称之为“油漆工模式”它是一种对象结构型模式。 在mybatis中缓存的功能由根接口Cacheorg.apache.ibatis.cache.Cache定义。关注Java技术栈微信公众号在后台回复关键字架构可以获取更多栈长整理的架构和设计模式干货。 整个体系采用装饰器设计模式数据存储和缓存的基本功能由PerpetualCacheorg.apache.ibatis.cache.impl.PerpetualCache永久缓存实现然后通过一系列的装饰器来对PerpetualCache永久缓存进行缓存策略等方便的控制。如下图 用于装饰PerpetualCache的标准装饰器共有8个全部在org.apache.ibatis.cache.decorators包中 FifoCache先进先出算法缓存回收策略 LoggingCache输出缓存命中的日志信息 LruCache最近最少使用算法缓存回收策略 ScheduledCache调度缓存负责定时清空缓存 SerializedCache缓存序列化和反序列化存储 SoftCache基于软引用实现的缓存管理策略 SynchronizedCache同步的缓存装饰器用于防止多线程并发访问 WeakCache基于弱引用实现的缓存管理策略 另外还有一个特殊的装饰器TransactionalCache事务性的缓存 正如大多数持久层框架一样mybatis缓存同样分为一级缓存和二级缓存 一级缓存又叫本地缓存是PerpetualCache类型的永久缓存保存在执行器中BaseExecutor而执行器又在SqlSessionDefaultSqlSession中所以一级缓存的生命周期与SqlSession是相同的。 二级缓存又叫自定义缓存实现了Cache接口的类都可以作为二级缓存所以可配置如encache等的第三方缓存。二级缓存以namespace名称空间为其唯一标识被保存在Configuration核心配置对象中。 二级缓存对象的默认类型为PerpetualCache如果配置的缓存是默认类型则mybatis会根据配置自动追加一系列装饰器。 Cache对象之间的引用顺序为 SynchronizedCache–LoggingCache–SerializedCache–ScheduledCache–LruCache–PerpetualCache 9、迭代器模式 迭代器Iterator模式又叫做游标Cursor模式。GOF给出的定义为提供一种方法访问一个容器container对象中各个元素而又不需暴露该对象的内部细节。  Java的Iterator就是迭代器模式的接口只要实现了该接口就相当于应用了迭代器模式 比如Mybatis的PropertyTokenizer是property包中的重量级类该类会被reflection包中其他的类频繁的引用到。这个类实现了Iterator接口在使用时经常被用到的是Iterator接口中的hasNext这个函数。 public class PropertyTokenizer implements IteratorPropertyTokenizer {private String name;private String indexedName;private String index;private String children;public PropertyTokenizer(String fullname) {int delim fullname.indexOf(.);if (delim -1) {name fullname.substring(0, delim);children fullname.substring(delim  1);} else {name fullname;children  null;}indexedName name;delim name.indexOf([);if (delim -1) {index name.substring(delim  1, name.length() - 1);name name.substring(0, delim);}}public String getName() {return name;}public String getIndex() {return index;}public String getIndexedName() {return indexedName;}public String getChildren() {return children;}Overridepublic boolean hasNext() {return children ! null;}Overridepublic PropertyTokenizer next() {return new PropertyTokenizer(children);}Overridepublic void remove() {throw new UnsupportedOperationException(Remove is not supported, as it has no meaning in the context of properties.);} } 可以看到这个类传入一个字符串到构造函数然后提供了iterator方法对解析后的子串进行遍历是一个很常用的方法类。
http://www.pierceye.com/news/487851/

相关文章:

  • 查公司的网站有哪些wordpress连接数据库出错
  • 找别人做网站需要什么信息湛江制作公司网站
  • 最简单的静态网站wordpress网络公司主题
  • 做外贸要做什么网站企业服务平台app下载
  • .net做网站开发吗企业网站维护合同
  • 有哪些做网站公司网站做关键词库的作用
  • 安全狗网站白名单指什么申请制作网站
  • 如何做高端网站建设香水推广软文
  • 移动网站建设优势优化设计电子课本下载
  • 做外贸英语要什么网站免费做app网站建设
  • 网站统计系统 怎么做遵义公共资源交易中心官网
  • 做外贸的有哪些网站廊坊网站建设公司哪个好
  • 深圳宝安网站建设学习网html5网页代码大全
  • 网站建设介绍会发言稿wordpress 工具栏
  • 重庆网站推广计划2017主流网站风格
  • 进贤网站建设做网站有什么优势
  • 免费购物网站源码网站收录是什么意思
  • 网站做端口映射如何创建公众号的步骤
  • 什么行业需要做网站网站系统升级需要多久
  • 网站产品推广网站建设功能规划
  • 2018年公司做网站注意事项WordPress标题美化
  • 西宁seo网站上海建设安检站网站
  • 网站友情链接模块介绍邯郸公司做网站
  • 怎样用织梦建设网站报个电脑培训班要多少钱
  • 河南省住房和城乡建设部网站首页安徽建设工程信息平台
  • 网站开发工程师的要求做seo要明白网站内容
  • 如何做天猫网站医学ppt模板免费下载网站
  • 网站上的通话功能怎么做网站用不用备案
  • 信誉好的模板网站建设wordpress 伪静态设置
  • wordpress主题外贸网站wordpress检查php版本号