我々は、すべての23個のデザインパターンがあることを知っているが、ほとんどは概念レベルで残るものの、実際の開発はめったに遭遇しません。MyBatisのソースは、デザインパターンのより深い理解が可能なアプリケーションで観察されたソースコードとデザインパターンを読んで、デザインパターンの多くを使用しています。
少なくとも以下のデザインパターンでMyBatisの出会い:
1、ビルダー模式、例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder。
2、工場モード、例えばSqlSessionFactory、のObjectFactory、MapperProxyFactory。
3、シングルトン、例えばErrorContextそしてたLogFactory。
図4は、プロキシモード、コアMyBatisの動的プロキシJDKで、このようなMapperProxy、ConnectionLoggerを実装し、また効果JavassistののCGLIBまたは遅延ローディングを達成するために使用executor.loaderパッケージ。
図5に示すように、複合モード、例えばSqlNode各サブクラスChooseSqlNode等。
図6に示すように、テンプレートの方法、例えばBaseExecutorとSimpleExecutor、ならびにすべてのサブクラスとBaseTypeHandler例えばIntegerTypeHandler。
図7に示すように、アダプタモード、例えば、その適応JDBCは、ログMyBatisのインターフェイスの他のロギングフレームワークをLOG4J。
8、Decoratorパターン、例えばキャッシュパッケージメディアは、各サブパケットcache.decoratorsデコレータを実現します。
9、反復モードそのような反復モードPropertyTokenizerとして、。
そして、解釈の1モードでは、最初に導入されたモデルのモデルを適用する方法でMyBatisの中に自分の知識や解釈ずつ。
1、ビルダーモード
パターンは、Builderが「同じビルドプロセスは異なる表現を作成できるように、オブジェクトとその分離の複雑な表現を構築します。」に定義され、作成したクラスパターンに属します。
オブジェクトはコンストラクタの範囲が含まれていることができますを超えて、より複雑な構築することである場合、一般的に、あなたは工場出荷時のモードとモードBuilderを使用することができます。
完全な製品に関して、工場出荷時の出力モード、Builderは、製品の一部のみを構築し、より複雑なオブジェクトを構築するために適用される、と。
初期MyBatisの環境中に、SqlSessionFactoryBuilderはXMLConfigBuilder MybatisMapConfig.xmlは、すべてのファイルを読み込み、すべての* Mapper.xmlビルドコアの構成はSqlSessionFactoryオブジェクトを構築するためのパラメータとして、MyBatisの実行をオブジェクト、[構成オブジェクトオブジェクトを呼び出します。
どこXMLConfigBuilder Configurationオブジェクトを構築する場合、とも呼ばれるXMLMapperBuilder *マッパーは、すべてのSQL文を読んで構築するために、ファイルを読み取るために使用されるが、XMLMapperBuilder使用XMLStatementBuilderされます。
このプロセスでは、生成物を反映して、これらのファイルまたは構成Builderを読み、[XpathParser解像度、構成や文法、構文解析の多くを行うことができます同様の機能が、結果は、キャッシュおよび他のステップに保存されているので、多くの仕事がありますそれはコンストラクタを含めるため、モデルを解決するためのビルダーの多くを使用することはできません。
:ビルダーコンクリートクラスについて、方法は、ほとんどそのようなことを含む方法、例えば、のように、*で始まるSqlSessionFactoryBuilderを構築している
、すなわち、工場SqlSessionFactory異なる入力パラメータに応じてオブジェクトを構築します。
2、工場パターン
そのようなSqlSessionFactory MyBatisの工場パターンは、植物より少ない複雑なロジック、単純なファクトリパターンに使用されます。
単純なファクトリパターン(単純な工場パターン):クラスに属する静的ファクトリメソッドとして知られている(静的ファクトリメソッド)モードでは、スキーマを作成します。
シンプルモードでは、工場は、異なるパラメータに応じて異なるクラスのインスタンスを返すことができます。インスタンスを作成するための責任を他のクラスに特別なクラスを定義するための単純なファクトリパターン、インスタンスは通常、共通の親クラスを持って作成されます。
SQLSESSIONは、アクセスマッパー、SQL文は、このインタフェースを介して実行可能な管理業務を実行し、MyBatisの作業インタフェースコアとみなすことができます。Connectionオブジェクトは、MySQLの接続に似ています。
あなたはすなわち、入力はautoCommit、エグゼキュータ、トランザクションとSQLSESSIONオブジェクトのコアを構築するために、他のパラメータをサポートし、ファクトリメソッドはたくさんのオーバーロード、のOpenSessionを見ることができます。
デフォルトのファクトリ実装DefaultSqlSessionFactoryのでは、我々が見ることができる方法がありますどのように製品の工場出荷時の出力:
これは、コンフィギュレーションに対応した環境設定を読み始めるのOpenSession基礎となるメソッド呼び出し、で、その後、トランザクションオブジェクトの初期化たTransactionFactoryを取得
その後の取引を通じて、最終的には構成によってエグゼキュータオブジェクトを取得し、エグゼキュータは自動コミットするかどうかを3つのパラメータがSQLSESSIONを建てました。
在这里其实也可以看到端倪,SqlSession的执行,其实是委托给对应的Executor来进行的。
而对于LogFactory,它的实现代码:
这里有个特别的地方,Log变量的的类型是Constructorextends Log>
也就是说该工厂生产的不只是一个产品,而是具有Log公共接口的一系列产品,比如Log4jImpl、Slf4jImpl等很多具体的Log。
3、单例模式
单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
单例模式是一种对象创建型模式,单例模式又名单件模式或单态模式。
在Mybatis中有两个地方用到单例模式,ErrorContext和LogFactory,其中ErrorContext是用在每个线程范围内的单例,用于记录该线程的执行环境错误信息
而LogFactory则是提供给整个Mybatis使用的日志工厂,用于获得针对项目配置好的日志对象。
ErrorContext的单例实现代码:
构造函数是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)来生成一个具体的代理:
在这里,先通过T newInstance(SqlSession sqlSession)方法会得到一个MapperProxy对象,然后调用T newInstance(MapperProxymapperProxy)生成代理对象然后返回。
而查看MapperProxy的代码,可以看到如下内容:
非常典型的,该MapperProxy类实现了InvocationHandler接口,并且实现了该接口的invoke方法。
通过这种方式,我们只需要编写Mapper.java接口类,当真正执行一个Mapper接口的时候,就会转发给MapperProxy.invoke方法
而该方法则会调用后续的sqlSession.cud>executor.execute>prepareStatement等一系列方法,完成SQL的执行和返回。
5、组合模式
组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。
组合模式对单个对象(叶子对象)和组合对象(组合对象)具有一致性,它将对象组织到树结构中,可以用来描述整体与部分的关系。
同时它也模糊了简单元素(叶子对象)和复杂元素(容器对象)的概念,使得客户能够像处理简单元素一样来处理复杂元素,从而使客户程序能够与复杂元素的内部结构解耦。
在使用组合模式中需要注意一点也是组合模式最关键的地方:叶子对象和组合对象实现相同的接口。这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。
Mybatis支持动态SQL的强大功能,比如下面的这个SQL:
在这里面使用到了trim、if等动态元素,可以根据条件来生成不同情况下的SQL;
在DynamicSqlSource.getBoundSql方法里,调用了rootSqlNode.apply(context)方法,apply方法是所有的动态节点都实现的接口:
对于实现该SqlSource接口的所有节点,就是整个组合模式树的各个节点:
组合模式的简单之处在于,所有的子节点都是同一类节点,可以递归的向下执行,比如对于TextSqlNode,因为它是最底层的叶子节点,所以直接将对应的内容append到SQL语句中:
但是对于IfSqlNode,就需要先做判断,如果判断通过,仍然会调用子元素的SqlNode,即contents.apply方法,实现递归的解析。
6、模板方法模式
模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。
模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。
代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。
模板类定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
在Mybatis中,sqlSession的SQL执行,都是委托给Executor实现的,Executor包含以下结构:
其中的BaseExecutor就采用了模板方法模式,它实现了大部分的SQL执行逻辑,然后把以下几个方法交给子类定制化完成:
该模板方法类有几个子类的具体实现,使用了不同的策略:
- 简单SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。(可以是Statement或PrepareStatement对象)
- 重用ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。(可以是Statement或PrepareStatement对象)
- 批量BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理的;BatchExecutor相当于维护了多个桶,每个桶里都装了很多属于自己的SQL,就像苹果蓝里装了很多苹果,番茄蓝里装了很多番茄,最后,再统一倒进仓库。(可以是Statement或PrepareStatement对象)
比如在SimpleExecutor中这样实现update方法:
7、适配器模式
适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
在Mybatsi的logging包中,有一个Log接口:
该接口定义了Mybatis直接使用的日志方法,而Log接口具体由谁来实现呢?
Mybatis提供了多种日志框架的实现,这些实现都匹配这个Log接口所定义的接口方法,最终实现了所有外部日志框架到Mybatis日志包的适配:
比如对于Log4jImpl的实现来说,该实现持有了org.apache.log4j.Logger的实例,然后所有的日志方法,均委托该实例来实现。
8、装饰者模式
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。
其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。
根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。
在mybatis中,缓存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(org.apache.ibatis.cache.impl.PerpetualCache)永久缓存实现,然后通过一系列的装饰器来对PerpetualCache永久缓存进行缓存策略等方便的控制。
如下图:
用于装饰PerpetualCache的标准装饰器共有8个(全部在org.apache.ibatis.cache.decorators包中):
1、FifoCache:先进先出算法,缓存回收策略
2、LoggingCache:输出缓存命中的日志信息
3、LruCache:最近最少使用算法,缓存回收策略
4、ScheduledCache:调度缓存,负责定时清空缓存
5、SerializedCache:缓存序列化和反序列化存储
6、SoftCache:基于软引用实现的缓存管理策略
7、SynchronizedCache:同步的缓存装饰器,用于防止多线程并发访问
8、WeakCache:基于弱引用实现的缓存管理策略
另外,还有一个特殊的装饰器TransactionalCache:事务性的缓存
正如大多数持久层框架一样,mybatis缓存同样分为一级缓存和二级缓存
- 一级缓存,又叫本地缓存,是PerpetualCache类型的永久缓存,保存在执行器中(BaseExecutor),而执行器又在SqlSession(DefaultSqlSession)中,所以一级缓存的生命周期与SqlSession是相同的。
- 二次キャッシュ実装インタフェースが二次キャッシュとして使用できることがカスタム・キャッシュと呼ばれるキャッシュ・クラスは、その第三者などencacheキャッシュように構成されてもよいです。そのユニークな識別子の名前空間の名前空間への二次キャッシュが設定コア構成オブジェクトに格納されています。
二次キャッシュオブジェクトPerpetualCacheのデフォルト・タイプ、デフォルト設定では、キャッシュ・タイプ場合、自動的にデコレータ構成の一連に従って添付MyBatisの。
Cacheオブジェクト間の引用順:
SynchronizedCache-> LoggingCache-> SerializedCache-> ScheduledCache-> LruCache-> PerpetualCache
9、イテレータパターン
また、カーソル(カーソル)モードとして知ら反復子(イテレータ)モード。与えられた定義GOF:オブジェクトの詳細を露出することなく、容器(コンテナ)オブジェクトの個々の要素にアクセスするための方法を提供します。
Javaのイテレータイテレータパターンは長い実装インタフェース、イテレータパターンのアプリケーションの等価な限り、インタフェースである:
例えばPropertyTokenizerのMyBatisのは、しばしば、他のクラスで反射パッケージになりプロパティパッケージヘビークラスでありますへの参照。使用中のこのクラスが実装Iteratorインターフェイスは、頻繁のhasNext Iteratorインターフェイス機能を使用しています。
それは文字列型は、コンストラクタに渡されたことが分かると、解析ストリングを横断した後にメソッド・イテレータを提供することができ、一般的に使用される方法のクラスです。