Hepimiz biliyoruz ki 26 tasarım deseni var, çoğu kavramsal seviyede kalıyor.Gerçek geliştirmede nadiren karşılaşılıyor.Mybatis kaynak kodunda çok sayıda tasarım deseni kullanılıyor.Kaynak kodunu okumak ve tasarım modellerinin uygulanmasını gözlemlemek daha derinlemesine olabilir. Tasarım modellerini anlayın.
Mybatis, en azından aşağıdaki tasarım modelleriyle karşılaştı:
Daha sonra, kalıpları tek tek açıklayacağım, önce kalıbın bilgisini tanıtacağım ve ardından kalıbın Mybatis'te nasıl uygulanacağını açıklayacağım.
Oluşturucu modunun tanımı, "karmaşık bir nesnenin yapısını temsilinden ayırmaktır, böylece aynı inşa süreci farklı temsiller yaratabilir." Oluşturma moduna aittir. Genel olarak, bir nesnenin yapısı daha karmaşıksa, ötesinde Yapıcı işlevinin kapsamı ile fabrika modunu ve kurucu modunu kullanabilirsiniz.Fabrika modu ile karşılaştırıldığında tam bir ürün üretilecektir.İnşaatçı, daha karmaşık nesnelerin veya hatta ürünün sadece bir kısmının inşası için kullanılır. "Effective-java" daki 2. maddede ayrıca şunlar belirtilmektedir: Birden çok yapıcı parametresiyle karşılaştığınızda, Oluşturucu modunu kullanmayı düşünün .
Oluşturucu modu
Mybatis ortamının başlatma sürecinde SqlSessionFactoryBuilder, tüm MybatisMapConfig.xml ve tüm * Mapper.xml dosyalarını okumak için XMLConfigBuilder'ı çağıracak, Mybatis'in çalıştırdığı temel nesne Configuration nesnesini oluşturacak ve ardından Configuration nesnesini parametre olarak içeren bir SqlSessionFactory nesnesi oluşturacaktır.
XMLConfigBuilder Configuration nesnesini oluşturduğunda, XMLMapperBuilder'ı * .Mapper dosyalarını okumak için de çağırır ve XMLMapperBuilder tüm SQL ifadelerini okumak ve oluşturmak için XMLStatementBuilder'ı kullanır.
Bu süreçte benzer bir özellik var, yani bu Builders dosyaları veya konfigürasyonları okuyacak ve daha sonra çok sayıda XpathParser ayrıştırma, yapılandırma veya gramer ayrıştırma, yansıma üreten nesneler ve bunları sonuç önbelleğinde depolayacaklar. Bir kurucu dahil edemez, bu yüzden çözmek için Oluşturucu modunun çok kullanımı.
Belirli oluşturucu sınıfları için çoğu yöntem build * ile başlar. Örneğin, SqlSessionFactoryBuilder, örneğin, aşağıdaki yöntemleri içerir:
SqlSessionFactoryBuilder
Diğer bir deyişle, SqlSessionFactory fabrika nesnesi farklı girdi parametrelerine göre oluşturulur.
Örneğin Mybatis'te SqlSessionFactory, karmaşık mantığa sahip olmayan ancak basit bir fabrika modeli olan fabrika modelini kullanır.
Basit Fabrika Modeli (Basit Fabrika Modeli): Statik Fabrika Yöntemi (Statik Fabrika Yöntemi) kalıbı olarak da bilinir, sınıf oluşturma modeline aittir. Basit fabrika modelinde, farklı sınıfların örnekleri farklı parametrelere göre döndürülebilir. Basit fabrika modeli, özellikle diğer sınıfların örneklerini oluşturmaktan sorumlu bir sınıfı tanımlar ve oluşturulan örnekler genellikle ortak bir ana sınıfa sahiptir.
Basit fabrika modeli
SqlSession, Mybatis çalışmasının temel bir arabirimi olarak düşünülebilir.Bu arabirim aracılığıyla, SQL deyimlerini çalıştırabilir, Mappers elde edebilir ve işlemleri yönetebilirsiniz. MySQL'e bağlanan Connection nesnesine benzer.
SqlSessionFactory
Factory'nin openSession () yönteminin, çekirdek SqlSession nesnesini oluşturmak için sırasıyla autoCommit, Executor, Transaction ve diğer parametrelerin girişini destekleyen birçok aşırı yüklemeye sahip olduğu görülebilir.
DefaultSqlSessionFactory'nin varsayılan fabrika uygulamasında, fabrikanın bir ürünü nasıl ürettiğini görmenin bir yolu vardır:
özel SqlSession openSessionFromDataSource (ExecutorType execType, TransactionIsolationLevel seviyesi, boolean autoCommit) { İşlem tx = boş; Deneyin { son Ortam ortamı = configuration.getEnvironment (); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment (ortam); tx = transactionFactory.newTransaction (environment.getDataSource (), level, autoCommit); final Yürütücü yürütücü = configuration.newExecutor (tx, execType); yeni DefaultSqlSession döndür (konfigürasyon, yürütücü, autoCommit); } catch (İstisna e) { closeTransaction (tx); // bir bağlantı getirmiş olabilir, bu yüzden // kapat() ExceptionFactory.wrapException ("Oturum açılırken hata oluştu. Neden:" + e, e); } en sonunda { ErrorContext.instance (). Reset (); } }Bu, openSession tarafından adlandırılan düşük seviyeli bir yöntemdir. Yöntem, önce yapılandırmadan ilgili ortam yapılandırmasını okur, ardından bir Transaction nesnesi elde etmek için TransactionFactory'yi başlatır, ardından Transaction aracılığıyla bir Executor nesnesi elde eder ve son olarak bunu üç parametre ile oluşturur: configuration, Executor ve autoCommit SqlSession.
Aslında, ipucunu burada da görebilirsiniz, SqlSession'ın yürütülmesi aslında ilgili Yürütücüye delege edilmiştir.
LogFactory için uygulama kodu:
public final class LogFactory { özel statik Oluşturucu < ? Günlüğü uzatır > logConstructor; özel LogFactory () { // inşaatı devre dışı bırak } genel statik Günlük getLog (Sınıf < ? > Bir sınıf) { getLog (aClass.getName ()); }Burada özel bir yer var, Log değişkeninin türü Constructor < ? extendsLog > , Bu, fabrikanın yalnızca bir ürün değil, Log4jImpl, Slf4jImpl ve diğer birçok belirli Logs gibi Log ortak arabirimlerine sahip bir dizi ürün ürettiği anlamına gelir.
Singleton Pattern: Singleton pattern, belirli bir sınıfın sadece bir örneğe sahip olmasını sağlar ve kendisini başlatır ve bu örneği tüm sisteme sağlar.Bu sınıfa, global erişim için yöntemler sağlayan tekli sınıf adı verilir.
Singleton modelinin üç ana noktası vardır: birincisi, belirli bir sınıfın yalnızca bir örneğe sahip olabileceğidir; diğeri, bu örneği kendi başına yaratması gerektiğidir; üçüncüsü, bu örneği tüm sisteme kendi başına sağlamalıdır. Tekli mod, bir nesne oluşturma modudur. Tekli mod ayrıca bir liste modu veya tek durum modudur.
Tekli mod
Mybatis, ErrorContext ve LogFactory'de tekli modu kullanmak için iki yer vardır; burada ErrorContext, iş parçacığının yürütme ortamı hata bilgilerini kaydetmek için her iş parçacığında kullanılan bir tekildir ve LogFactory tüm Mybatis'e sağlanır. Kullanılan günlük fabrikası, proje için yapılandırılmış günlük nesnelerini elde etmek için kullanılır.
ErrorContext'in Singleton uygulama kodu:
public class ErrorContext { özel statik final ThreadLocal < ErrorContext > YEREL = yeni ThreadLocal < ErrorContext > (); private ErrorContext () { } public statik ErrorContext örneği () { ErrorContext bağlam = YEREL.get (); eğer (bağlam == null) { bağlam = yeni ErrorContext (); LOCAL.set (içerik); } dönüş bağlamı; }Yapıcı, statik bir yerel örnek değişkeni ve bir örnek değişkeni elde etmek için bir yöntem içeren özel bir değişikliktir.Bir örnek elde etme yönteminde, önce boş olup olmadığı belirlenir.Eğer öyleyse, önce oluşturulur ve sonra oluşturulan nesne döndürülür.
Buradaki tek ilginç şey, LOCAL'ın statik örnek değişkeninin ThreadLocal ile dekore edilmiş olmasıdır, bu da her bir iş parçacığının ilgili verilerine ait olduğu anlamına gelir. İnstance () yönteminde, yoksa önce bu iş parçacığının örneğini alın Bu iş parçacığına özgü bir ErrorContext oluşturun.
Proxy modu, Mybatis tarafından kullanılan temel mod olarak düşünülebilir. Bu mod nedeniyle, yalnızca Mapper.java arayüzünü yazmamız gerekir ve uygulanmasına gerek yoktur. Mybatis arka ucu, belirli SQL yürütmesini tamamlamamıza yardımcı olacaktır.
Proxy Kalıbı: Bir nesne için bir proxy sağlar ve proxy nesnesi, orijinal nesneye olan başvuruyu kontrol eder. Proxy modu için İngilizce sözcük, bir nesne yapısı modu olan Proxy veya Surrogate olarak adlandırılır.
Proxy modu aşağıdaki rolleri içerir:
Ajans modeli
Burada iki adım var, birincisi önceden bir Proxy oluşturmak, ikincisi kullanıldığında Proxy'yi otomatik olarak talep etmek ve ardından Proxy belirli işlemleri gerçekleştirecek;
Yapılandırmanın getMapper yöntemini kullandığımızda, mapperRegistry.getMapper yöntemini çağıracağız ve bu da belirli bir proxy oluşturmak için mapperProxyFactory.newInstance (sqlSession) 'u çağıracaktır:
/ ** * @author Lasse Voss * / public class MapperProxyFactory < T > { özel final Sınıfı < T > mapperInterface; özel final Haritası < Yöntem, Eşleyici Yöntem > methodCache = new ConcurrentHashMap < Yöntem, Eşleyici Yöntem > (); public MapperProxyFactory (Sınıf < T > mapperInterface) { this.mapperInterface = mapperInterface; } Kamusal sınıf < T > getMapperInterface () { dönüş mapperInterface; } genel Harita < Yöntem, Eşleyici Yöntem > getMethodCache () { dönüş methodCache; } @SuppressWarnings ("kontrol edilmemiş") korumalı T newInstance (MapperProxy < T > mapperProxy) { return (T) Proxy.newProxyInstance (mapperInterface.getClassLoader (), yeni Sınıf {mapperInterface}, mapperProxy); } public T newInstance (SqlSession sqlSession) { final MapperProxy < T > mapperProxy = yeni MapperProxy < T > (sqlSession, mapperInterface, methodCache); return newInstance (mapperProxy); } }Burada, önce T newInstance (SqlSession sqlSession) yöntemi aracılığıyla bir MapperProxy nesnesi alın ve ardından T newInstance (MapperProxy < T > mapperProxy) bir proxy nesnesi oluşturur ve geri döner.
MapperProxy koduna baktığınızda şunları görebilirsiniz:
public class MapperProxy < T > InvocationHandler, Serializable { @Override public Object invoke (Object proxy, Method method, Object args) Throwable { Deneyin { eğer (Object.class.equals (method.getDeclaringClass ())) { return method.invoke (this, args); } else if (isDefaultMethod (yöntem)) { return invokeDefaultMethod (proxy, yöntem, değiştirgeler); } } catch (Fırlatılabilir t) { throw ExceptionUtil.unwrapThrowable (t); } final MapperMethod mapperMethod = cachedMapperMethod (yöntem); return mapperMethod.execute (sqlSession, args); }Çok tipik olarak, MapperProxy sınıfı InvocationHandler arabirimini uygular ve arabirimin çağırma yöntemini uygular.
Bu şekilde, sadece Mapper.java arayüz sınıfını yazmamız gerekiyor.Bir Mapper arayüzü gerçekten çalıştırıldığında, MapperProxy.invoke metoduna yönlendirilecek ve bu metot sonraki sqlSession.cud'u çağıracaktır. > executor.execute > ReadyStatement gibi bir dizi yöntem, SQL'in yürütülmesini ve geri döndürülmesini tamamlar.
Kombinasyon modu, "tam bölüm" yapı hiyerarşisini temsil edecek bir ağaç yapısı oluşturmak için birden çok nesneyi birleştirir.
Kombinasyon modu, tek nesneler (yaprak nesneler) ve birleştirilmiş nesneler (birleşik nesneler) için tutarlılığa sahiptir.Nesneleri bir ağaç yapısı halinde düzenler ve bütün ile parça arasındaki ilişkiyi tanımlamak için kullanılabilir. Aynı zamanda, basit öğeler (yaprak nesneler) ve karmaşık öğeler (kap nesneleri) kavramlarını bulanıklaştırarak müşterilerin karmaşık öğeleri basit öğeler olarak işlemesine olanak tanır, böylece istemci programları karmaşık öğelerin dahili yapısından ayrılabilir.
Bileşik modu kullanırken dikkat edilmesi gereken bir nokta, bileşik modun en kritik kısmıdır: yaprak nesne ve bileşik nesne aynı arayüzü uygular. Bu nedenle, birleşik mod, yaprak düğümlerini ve nesne düğümlerini tutarlı bir şekilde işleyebilir.
Kombinasyon modu
Mybatis, aşağıdaki SQL gibi dinamik SQL'in güçlü işlevlerini destekler:
< update id = "update" parameterType = "org.format.dynamicproxy.mybatis.bean.User" > UPDATE kullanıcıları < trim prefix = "SET" prefixOverrides = "," > < eğer test = "isim! = boş ve isim! = ''" > isim = # {isim} < /Eğer > < test = "yaş! = boş ve yaş! = ''" ise > , yaş = # {age} < /Eğer > < eğer test = "doğum günü! = boş ve doğum günü! = ''" > , doğum günü = # {doğum günü} < /Eğer > < / trim > id = $ {id} nerede < /Güncelleme >Burada trim ve if gibi dinamik öğeler kullanılır ve farklı durumlarda SQL, koşullara göre oluşturulabilir;
DynamicSqlSource.getBoundSql yönteminde, rootSqlNode.apply (bağlam) yöntemi çağrılır. Apply yöntemi, tüm dinamik düğümler tarafından uygulanan bir arabirimdir:
genel arayüz SqlNode { boole uygulaması (DynamicContext bağlamı); }SqlSource arabirimini uygulayan tüm düğümler için, bu, tüm birleşik desen ağacının her bir düğümüdür:
SqlNode
Birleşik modun basitliği, tüm alt düğümlerin aynı türden olması ve aşağı doğru yinelemeli olarak çalıştırılabilmesidir.Örneğin, TextSqlNode için, alt yaprak düğüm olduğu için, karşılık gelen içerik doğrudan SQL deyimine eklenir:
@Override public boolean apply (DynamicContext bağlamı) { GenericTokenParser ayrıştırıcı = createParser (yeni BindingTokenParser (bağlam, injectionFilter)); context.appendSql (parser.parse (metin)); doğruya dön; }Ancak IfSqlNode için önce bir karar vermeniz gerekir.Eğer yargı geçilirse, alt öğenin SqlNode'u, yani content.apply yöntemi, yinelemeli analizi gerçekleştirmek için yine de çağrılacaktır.
@Override public boolean apply (DynamicContext bağlamı) { if (evaluator.evaluateBoolean (test, context.getBindings ())) { içindekiler.apply (bağlam); doğruya dön; } yanlış dönüş; }Şablon yöntemi modeli, tüm modeller arasında en yaygın modellerden biridir ve kalıtıma dayalı kod yeniden kullanımının temel tekniğidir.
Şablon yöntem modeli, soyut sınıflar ve somut alt sınıflar geliştiren tasarımcılar arasında işbirliği gerektirir. Bir tasarımcı bir algoritmanın ana hatlarını ve iskeletini vermekten sorumluyken, diğer tasarımcılar algoritmanın mantıksal adımlarını vermekten sorumludur. Bu belirli mantıksal adımları temsil eden yönteme ilkel yöntem denir ve bu temel yöntemleri özetleyen yönteme şablon yöntemi denir ve bu tasarım modelinin adı buradan gelir.
Şablon sınıfı, işlemdeki bir algoritmanın iskeletini tanımlar ve alt sınıflara giden bazı adımları geciktirir. Bu, alt sınıfların, bir algoritmanın yapısını değiştirmeden bir algoritmanın belirli belirli adımlarını yeniden tanımlamasına izin verir.
Şablon yöntemi modeli
Mybatis'te, sqlSession'ın SQL yürütmesinin tamamı Executor'a devredilir.Executor aşağıdaki yapıyı içerir:
Yürütücü arayüzü
Bunların arasında BaseExecutor, SQL yürütme mantığının çoğunu uygulayan şablon yöntemi modunu benimser ve ardından aşağıdaki yöntemler, özelleştirme için alt sınıfa aktarılır:
@Override public boolean apply (DynamicContext bağlamı) { if (evaluator.evaluateBoolean (test, context.getBindings ())) { içindekiler.apply (bağlam); doğruya dön; } yanlış dönüş; }Şablon yöntemi sınıfı, farklı stratejiler kullanan birkaç somut alt sınıf uygulamasına sahiptir:
Örneğin, SimpleExecutor'da güncelleme yöntemini şu şekilde uygulayın:
@Override public int doUpdate (MappedStatement ms, Object parametresi) SQLException { İfade stmt = null; Deneyin { Yapılandırma yapılandırması = ms.getConfiguration (); StatementHandler işleyicisi = configuration.newStatementHandler (this, ms, parametre, RowBounds.DEFAULT, null, boş); stmt = readyStatement (handler, ms.getStatementLog ()); dönüş işleyicisi.update (stmt); } en sonunda { closeStatement (stmt); } }Bağdaştırıcı Modeli: Bir arabirimi müşterinin istediği başka bir arabirime dönüştürün. Bağdaştırıcı modeli, arabirimle uyumsuz sınıfların birlikte çalışmasını sağlar ve diğer adı Wrapper'dır. Adaptör modeli, bir sınıf yapısı modeli veya bir nesne yapısı modeli olarak kullanılabilir.
Adaptör modu
Mybatsi'nin günlük kaydı paketinde bir Günlük arayüzü vardır:
/ ** * @author Clinton Begin * / genel arayüz Günlüğü { boole isDebugEnabled (); boole isTraceEnabled (); geçersiz hata (String s, Throwable e); geçersiz hata (Dizeler); geçersiz hata ayıklama (String ler); void trace (Dizeler); void warn (String ler); }Bu arayüz, doğrudan Mybatis tarafından kullanılan günlük yöntemini tanımlar ve Günlük arayüzünü kim uygular? Mybatis, tümü bu Log arabirimi tarafından tanımlanan arabirim yöntemleriyle eşleşen ve son olarak tüm harici günlük çerçevelerinin Mybatis günlük paketine uyarlanmasını gerçekleştiren çeşitli günlük çerçeve uygulamaları sağlar:
Kayıt
Örneğin, Log4jImpl uygulaması için uygulama, bir org.apache.log4j.Logger örneğini tutar ve ardından tüm günlük yöntemleri, uygulanması için bu örneğe delege edilir.
public class Log4jImpl, Log { private static final String FQCN = Log4jImpl.class.getName (); özel Kaydedici günlüğü; public Log4jImpl (String clazz) { log = Logger.getLogger (clazz); } @Override public boolean isDebugEnabled () { dönüş log.isDebugEnabled (); } @Override public boolean isTraceEnabled () { dönüş log.isTraceEnabled (); } @Override public void error (String s, Throwable e) { log.log (FQCN, Level.ERROR, s, e); } @Override public void error (String s) { log.log (FQCN, Level.ERROR, s, null); } @Override public void debug (String s) { log.log (FQCN, Level.DEBUG, s, null); } @Override public void trace (String ler) { log.log (FQCN, Level.TRACE, s, null); } @Override public void warn (String ler) { log.log (FQCN, Level.WARN, s, null); } }Dekoratör Modeli: Bir nesneye dinamik olarak bazı ek sorumluluklar (Sorumluluk) ekleyin Nesne işlevlerinin eklenmesi açısından, dekoratör modeli alt sınıflar oluşturmaktan daha esnektir. Diğer ad, adaptör deseninin takma adıyla aynı olan bir sarıcı olarak da adlandırılabilir, ancak bunlar farklı durumlar için uygundur. Farklı çevirilere göre, bazı kişiler, bir nesne yapı modu olan dekorasyon moduna "ressam modu" diyorlar.
Dekoratör modu
Mybatis'te önbelleğe alma işlevi, önbellek kök arabirimi (org.apache.ibatis.cache.Cache) tarafından tanımlanır. Tüm sistem dekoratör tasarım modelini benimser.Veri depolama ve önbelleğe almanın temel işlevleri PerpetualCache (org.apache.ibatis.cache.impl.PerpetualCache) kalıcı önbellek tarafından gerçekleştirilir ve ardından PerpetualCache kalıcı önbelleğini önbelleğe almak için bir dizi dekoratör kullanılır. Kullanışlı kontrol. Aşağıda gösterildiği gibi:
Önbellek
PerpetualCache'yi dekore etmek için kullanılan 8 standart dekoratör vardır (tümü org.apache.ibatis.cache.decorators paketinde):
Ek olarak, özel bir dekoratör TransactionalCache vardır: işlem önbelleği
Çoğu kalıcı katman çerçevesi gibi, mybatis önbelleği de birinci düzey önbelleğe ve ikinci düzey önbelleğe bölünmüştür
İkinci seviye önbellek nesnesinin varsayılan türü PerpetualCache'dir. Yapılandırılmış önbellek varsayılan türse, mybatis yapılandırmaya göre otomatik olarak bir dizi dekoratör ekleyecektir.
Önbellek nesneleri arasındaki referansların sırası şöyledir:
SynchronizedCache > LoggingCache > Serileştirilmiş Önbellek > ScheduledCache > LruCache > PerpetualCache
İmleç modu olarak da bilinen yineleyici modu. GOF tarafından verilen tanım şudur: Bir konteyner nesnesindeki her bir öğeye, nesnenin dahili ayrıntılarını ifşa etmeden erişmek için bir yöntem sağlayın.
Yineleyici modu
Java'nın Yineleyicisi, yineleyici modelinin arabirimidir. Arabirim uygulandığı sürece yineleyici modelini uygulamaya eşdeğerdir:
Yineleyici
Örneğin, Mybatis'in PropertyTokenizer'ı, yansıma paketindeki diğer sınıflar tarafından sıklıkla başvurulan, özellik paketindeki ağır bir sınıftır. Bu sınıf, Yineleyici arabirimini uygular.Yineleyici arabirimindeki hasNext işlevi, genellikle kullanılırken kullanılır.
public class PropertyTokenizer, Yineleyiciyi uygular < PropertyTokenizer > { özel Dize adı; private String indexedName; özel String indeksi; özel String çocukları; public PropertyTokenizer (Dize tam adı) { int sınırlandırıcı = tamad.indexOf ('.'); eğer (sınırlandır > -1) { ad = tamad.substring (0, sınırlandırıcı); çocuklar = tamad.substring (sınır + 1); } Başka { isim = tam isim; çocuklar = boş; } indexedName = isim; delim = name.indexOf ('