設(shè)計(jì)模式實(shí)踐(一)-框架源碼中的常見設(shè)計(jì)模式

前言

設(shè)計(jì)面向?qū)ο蟊容^困難描馅,而設(shè)計(jì)可復(fù)用的面向?qū)ο缶透永щy营勤!
設(shè)計(jì)模式的不是為了提高代碼的運(yùn)行效率富弦,而是提高開發(fā)效率沟娱!
設(shè)計(jì)模式使代碼編寫真正工程化,是軟件工程的的基石脈絡(luò)腕柜!
設(shè)計(jì)模式是軟件開發(fā)的葵花寶典济似,天下武功,無堅(jiān)不摧盏缤,唯快不破砰蠢!

一、裝飾器模式

通過組合的方式動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)或者行為

  • 在不影響其他對(duì)象的情況下唉铜,以動(dòng)態(tài)台舱、透明的方式給單個(gè)對(duì)象添加職責(zé),很契合設(shè)計(jì)模式原則之一開閉原則

  • 當(dāng)對(duì)象族實(shí)現(xiàn)復(fù)雜度已經(jīng)無法用繼承來實(shí)現(xiàn)(eg:可能有大量獨(dú)立的擴(kuò)展,

  • 裝飾類增加了系統(tǒng)的擴(kuò)展性竞惋,對(duì)單元測(cè)試友好

為支持每一種組合將產(chǎn)生大量的子類柜去,使得子類數(shù)目呈現(xiàn)組合疊加爆炸性增長(zhǎng))

  • 源碼套路
X x=new X1(new X2(new X3()))......

UML類圖

image

一層一層嵌套,"裝飾器類" 持有目標(biāo)對(duì)象的引用尖滚,具體方法執(zhí)行委托給具體的目標(biāo)對(duì)象子類形成了一連串"裝飾器鏈"丧裁,不斷地增強(qiáng)功能

應(yīng)用場(chǎng)景1

mybatis 二級(jí)緩存
  • 抽象組件實(shí)現(xiàn)類 (cache.impl包下)


    WechatIMG3.jpeg
  • 裝飾器族(cache.decorators包下)

WechatIMG4.jpeg
  • build模式構(gòu)建二級(jí)緩存
 Cache cache = new CacheBuilder(currentNamespace)
        .implementation(valueOrDefault(typeClass, PerpetualCache.class))
        .addDecorator(valueOrDefault(evictionClass, LruCache.class))
        .clearInterval(flushInterval)
        .size(size)
        .readWrite(readWrite)
        .blocking(blocking)
        .properties(props)
        .build();

  • 裝飾器入口
  if (PerpetualCache.class.equals(cache.getClass())) {
      for (Class<? extends Cache> decorator : decorators) {
        cache = newCacheDecoratorInstance(decorator, cache);
        setCacheProperties(cache);
      }
      cache = setStandardDecorators(cache);
    } else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
      cache = new LoggingCache(cache);
    }
 
  try {
      MetaObject metaCache = SystemMetaObject.forObject(cache);
      if (size != null && metaCache.hasSetter("size")) {
        metaCache.setValue("size", size);
      }
      if (clearInterval != null) {
        cache = new ScheduledCache(cache);
        ((ScheduledCache) cache).setClearInterval(clearInterval);
      }
      if (readWrite) {
        cache = new SerializedCache(cache);
      }
      cache = new LoggingCache(cache);
      cache = new SynchronizedCache(cache);
      if (blocking) {
        cache = new BlockingCache(cache);
      }
      return cache;
    } catch (Exception e) {
      throw new CacheException("Error building standard cache decorators.  Cause: " + e, e);
    }
四不四很符合X x=new X1(new X2(new X3()))......[呲牙]
  • 以FifoCache分析一下裝飾器的使用
 public class FifoCache implements Cache {
  private final Cache delegate;
  public FifoCache(Cache delegate) {
    this.delegate = delegate;
    this.keyList = new LinkedList<Object>();
    this.size = 1024;
  }
//put get實(shí)際上都委托給了PerpetualCache來實(shí)現(xiàn)
  public void putObject(Object key, Object value) {
    cycleKeyList(key);
    delegate.putObject(key, value);//增強(qiáng)了回收策略
  }
  public Object getObject(Object key) {
    return delegate.getObject(key);
  }
//增強(qiáng)的方法鹉动,先回收最先進(jìn)入的換成對(duì)象
 private void cycleKeyList(Object key) {
    keyList.addLast(key);
    if (keyList.size() > size) {
      Object oldestKey = keyList.removeFirst();
      delegate.removeObject(oldestKey);
    }
  }

Cache的設(shè)計(jì)上目標(biāo)類和裝飾器類實(shí)現(xiàn)了Cache接口,裝飾器一個(gè)一個(gè)裝飾器類串起來股耽,層層包裝目標(biāo)類形成一個(gè)鏈

增強(qiáng)的功能一覽

  • ScheduledCache:根據(jù)時(shí)間間隔清理緩存數(shù)據(jù)
  • LoggingCache:緩存命中率打印(debug)
  • LruCache:最近最少使用原則
  • SoftCache:jdk軟引用策略,jvm內(nèi)存不足時(shí)回收緩存對(duì)象
  • 等等.....

應(yīng)用場(chǎng)景2

JDK IO流
FileInputStream in=new FileInputStream(new File ("hello.txt"));

BufferedInputStream inBuffered=new BufferedInputStream (in);

BufferedInputStream是一層裝飾钳幅,增強(qiáng)了“緩沖區(qū)”的功能....

等等.....


二物蝙、模板設(shè)計(jì)模式

定義一個(gè)操作中算法的骨架或流程,充分利用"多態(tài)"使得子類可以不改變算法的結(jié)構(gòu)即可重新定義實(shí)現(xiàn)

適用場(chǎng)景

完成一件事情贡这,有固定的流程步驟比如說 1->2->3->4茬末,但是每個(gè)步驟根據(jù)子類對(duì)象的不同,而實(shí)現(xiàn)細(xì)節(jié)不同盖矫,就可以在父類中定義不變的方法丽惭,把可變的方法通過子類回調(diào)來實(shí)現(xiàn)

關(guān)鍵字: 回調(diào)

UML類圖

image
  • spring/mybatis/dubbo出現(xiàn)頻率較高,一般表現(xiàn)為抽象類+protected+abstract方法組合
  • 代碼套路
 public abstract class Abstractxxxxxx{
      
    public  void method{
         //校驗(yàn)邏輯
         //參數(shù)裝配
//業(yè)務(wù)邏輯1辈双、2责掏、3
         doMethod();
         //異常處理
         //資源清理
    }
    //抽象方法由子類實(shí)現(xiàn),父類回調(diào)...
    protected abstract void doMethod() ;
}

應(yīng)用場(chǎng)景1

mybatis executor執(zhí)行器

20151220224146815.jpg
  • BaseExecutor 模板抽象父類
  • SimpleExecutor 簡(jiǎn)單執(zhí)行器類湃望,常規(guī)的CURD
  • ReuseExecutor 復(fù)用Statement執(zhí)行器
  • BatchExecutor 批量update執(zhí)行器類
  • 抽象類BaseExecutor 查詢模板方法
  
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    一級(jí)二級(jí)緩存處理邏輯
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
      queryStack++;
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
        //真正的查詢db入口
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
   todo 一些清理方法换衬,緩存,事務(wù)证芭,連接關(guān)閉等等
   查詢db方法入口
 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
      todo一堆前置方法 校驗(yàn)瞳浦,緩存(不可變方法)
      doQuery是抽象方法,可變方法交給具體的子類去實(shí)現(xiàn)
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
      todo 一堆后置方法....(不可變方法)

//protected abstract 暗示著需要子類去實(shí)現(xiàn)
 protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
     
update/delete/insert套路同上
  • 實(shí)現(xiàn)類SimpleExecutor废士,真正的執(zhí)行器
public class SimpleExecutor extends BaseExecutor { 
  //真正查詢db的入口實(shí)現(xiàn)
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

方法調(diào)用叫潦,根據(jù)ExecutorType類型不同選擇不同的實(shí)現(xiàn)類

 sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
 sqlSession = sqlSessionFactory.openSession(ExecutorType.SIMPLE);

Executor選擇器入口

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
     //根據(jù)參數(shù)選擇執(zhí)行器實(shí)現(xiàn) -> 策略模式
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      //上文裝飾器的包裝入口 -> 裝飾器模式
      executor = new CachingExecutor(executor);
    }
   //插件攔截器鏈的入口-> 責(zé)任鏈模式
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

應(yīng)用場(chǎng)景2

消息中間件 消費(fèi)端-consumer處理消息
  • 消費(fèi)端子類實(shí)現(xiàn)類消費(fèi)邏輯
 private class MyHandle extends AbstractHandle {
        //子類方法實(shí)現(xiàn)父類,在抽象父類模板方法回調(diào)之官硝!
        public void doHandle(String data) {
            //消費(fèi)解析消息 todo...
        }
    }
  • consumer抽象類模板方法
public abstract class AbstractHandle implements IHandle{
    public void handle(message msg)  {
        //todo 前置處理省略
            try {
                //抽象方法由子類實(shí)現(xiàn)后矗蕊,回調(diào)...
                doHandle(data);
            } catch (  Exception ex) {
               //..todo
            }
        // 后置業(yè)務(wù)邏輯 todo 清理,日志氢架,異常捕獲等等
    }

三傻咖、策略模式

動(dòng)態(tài)的改變對(duì)象的行為,實(shí)現(xiàn)某一個(gè)功能有多種算法或者策略岖研,多種不同解決方案動(dòng)態(tài)切換卿操,起到改變對(duì)象行為的效果,一般會(huì)結(jié)合模板方法模式配合使用

  • UML類圖


應(yīng)用舉例1

jdk線程池拒絕策略

線程池構(gòu)造方法,其中RejectedExecutionHandler是拒絕策略的接口

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

策略接口

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

策略實(shí)現(xiàn)類



策略實(shí)現(xiàn)之一:線程池滿了硬纤,主線程執(zhí)行

 public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public CallerRunsPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

要實(shí)現(xiàn)自己的拒絕策略只需要實(shí)現(xiàn)拒絕接口即可

  • netty線程池拒絕策略
package org.jboss.netty.handler.execution;
private static final class NewThreadRunsPolicy implements RejectedExecutionHandler {
        NewThreadRunsPolicy() {
            super();
        }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            try {
                final Thread t = new Thread(r, "Temporary task executor");
                t.start();
            } catch (Throwable e) { }
        }
    }
  • dubbo線程模型線程池拒絕策略
package com.alibaba.dubbo.common.threadpool.support;
public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
    
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        String msg = String.format("Thread pool is EXHAUSTED!");
        logger.warn(msg);
        throw new RejectedExecutionException(msg);
    }
}

應(yīng)用舉例2

消息中間件的消費(fèi)模型
  • 客戶端根據(jù)實(shí)際情況選擇消費(fèi)策略算法
    客戶端依賴抽象類解滓,實(shí)現(xiàn)類依賴的抽象,一定程度上契合了依賴倒轉(zhuǎn)原則客戶端和實(shí)現(xiàn)類通過抽象類關(guān)聯(lián)在一起筝家。
 AbstractHandle handle = new MyHandle();
 handle.handle()

并行和串行子類實(shí)現(xiàn)handle()策略方法洼裤,從而對(duì)消息有不同的消費(fèi)策略
增強(qiáng)其他的消費(fèi)策略,實(shí)現(xiàn)抽象方法即可溪王,開閉自如


四腮鞍、外觀模式

定義了一個(gè)高層接口,為一堆子系統(tǒng)接口提供一個(gè)一致的entry入口莹菱,供客戶端調(diào)用

引入外觀角色之后移国,用戶只需要直接與外觀角色交互,用戶與子系統(tǒng)之間的復(fù)雜關(guān)系由外觀角色來實(shí)現(xiàn)道伟,從而降低了系統(tǒng)的耦合度迹缀。



可以看到經(jīng)過外觀模式改造后的子系統(tǒng)對(duì)于客戶端來說,封裝了內(nèi)部負(fù)載的實(shí)現(xiàn)邏輯蜜徽,對(duì)客戶端友好

  • UML類圖


  • 子系統(tǒng):職責(zé)單一祝懂,易于維護(hù)
  • 門面:充當(dāng)了客戶類與子系統(tǒng)類之間的“第三者”,對(duì)外隱藏了很多細(xì)節(jié)拘鞋,對(duì)客戶的來說"最少知道"砚蓬,比較契合迪米特法則。

應(yīng)用舉例

SLF4J

SLF4J = Simple Logging Facade for Java

  • slf4j相當(dāng)于一層門面facade盆色,日志框架的抽象灰蛙,提供了對(duì)日志子系統(tǒng)(log4j,logback,jdk-logging)的入口

工廠模式獲取當(dāng)前類的日志對(duì)象,對(duì)于具體的實(shí)現(xiàn)隔躲,客戶端是不知道的摩梧,實(shí)際使用是綁定具體實(shí)現(xiàn)類。
獲取日志子系統(tǒng)實(shí)現(xiàn)類通過類加載機(jī)制宣旱,按照加載順序仅父,第一個(gè)被加載到的子日志系統(tǒng)就綁定到slf4j。
子類加載和尋通過maven pom.xml配置

private final Logger logger = LoggerFactory.getLogger(this.getClass());


如圖所示响鹃,門面slf4j-api
log4j:根據(jù)橋接slf4j-log4j包適配log4j 驾霜,輸出由最終log4j.jar實(shí)現(xiàn)類執(zhí)行案训。
logback:直接實(shí)現(xiàn)了slf4j的接口买置,不需要橋接包的適配過程
子系統(tǒng)通過類加載機(jī)制來綁定具體的日志子系統(tǒng),"先到先得"

/*
很重要强霎,類加載器加載路徑忿项,slf4j日志子系統(tǒng)都要有同名的包類
根據(jù)類加載器雙親委托機(jī)制,第一個(gè)加載到的日志子系統(tǒng)就優(yōu)先使用
*/
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

  private static Set<URL> findPossibleStaticLoggerBinderPathSet() {
   
    Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
    try {
    //獲取類加載器
      ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
      Enumeration<URL> paths;
      if (loggerFactoryClassLoader == null) {
        paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
      } else {
        paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
      }
     
  • logback.jar包同名類



觀察者-事件監(jiān)聽模式

察者模式定義了對(duì)象之間的一對(duì)多的依賴關(guān)系,這樣,當(dāng)"一"的一方狀態(tài)發(fā)生變化時(shí),它所依賴的"多"的一方都會(huì)收到通知并觸發(fā)相關(guān)操作

  • 關(guān)系圖譜


    image.png
  • UML類圖


  • event-object:事件狀態(tài)對(duì)象轩触,作為監(jiān)聽器的參數(shù)參與事件交互
  • event0source:具體的事件源寞酿,被監(jiān)聽的對(duì)象
  • event listener:事件監(jiān)聽器,由事件源出發(fā)監(jiān)聽事件脱柱,引起響應(yīng)變化伐弹。

事件監(jiān)聽把事件源和監(jiān)聽器的的依賴關(guān)系徹底解耦
公眾號(hào)訂閱,訂閱報(bào)紙期刊榨为,數(shù)據(jù)庫(kù)觸發(fā)器等等都有觀察者模式的"味道"
基于事件驅(qū)動(dòng)機(jī)制的系統(tǒng)或語(yǔ)言惨好,比如 js、netty随闺,kafka等亦如此日川。
java-swing中的應(yīng)用比較多 button點(diǎn)擊事件 ....

應(yīng)用場(chǎng)景1

cuodao-kafka-consumer事件監(jiān)聽
  • kafka循環(huán)pull數(shù)據(jù) 即為"事件源",該事件源是一個(gè)線程
public class PullTask extends Thread {
  • kafka-consumer狀態(tài)變化 包裝為"事件"
/**
 * 消費(fèi)端工作者狀態(tài)發(fā)生變化的事件
 * @author cuodao
 */
public class TaskStatusEvent extends EventObject {
    private static final long serialVersionUID = 1298884648955658019L;

    private final TaskStatus oldStatus;

    private final TaskStatus newStatus;
  • TaskStatus 事件添加對(duì)應(yīng)監(jiān)聽器加以偵聽其狀態(tài)變化
   PullTask() {
            this.setDaemon(true);
            //添加監(jiān)聽器
            this.addListener(myListener());
        }
  • 事件狀態(tài)變化后引起的事件回調(diào)矩乐,修改consumer的全局狀態(tài)
        private TaskStatusListener myListener() {
            return new TaskStatusListener() {
                @Override
                public void statusListener(TaskStatusEvent e) {
                 
                    }

六龄句、適配器模式

將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口

  • UMl類圖(類適配器)


  • adpter也可以是抽象為接口,適配由子類實(shí)現(xiàn)
  • 對(duì)象適配器類圖類似散罕,adpter和adptee關(guān)系由繼承->關(guān)聯(lián)分歇,也就是委托
    業(yè)務(wù)代碼中,面向適配器開發(fā)可以拓展新功能笨使,這里適配器模式也有一點(diǎn)裝飾器的意思卿樱,只不過"動(dòng)機(jī)"不同!一個(gè)是單純的增強(qiáng)硫椰,一個(gè)是補(bǔ)償

應(yīng)用場(chǎng)景

mybatis 日志框架適配
  • target頂級(jí)日志接口
package org.apache.ibatis.logging;

/**
 * @author Clinton Begin
 */
public interface Log {

  boolean isDebugEnabled();
  void error(String s, Throwable e);
  debug
  tarce
  warn
  .....
}
  • log4j適配器類繁调,采用了對(duì)象適配-委托給"org.apache.log4j.Logger"
package org.apache.ibatis.logging.log4j;
import org.apache.ibatis.logging.Log;
import org.apache.log4j.Logger;

/**
 * @author Eduardo Macarron
 */
public class Log4jImpl implements Log {
  private Logger log;
  public void error(String s, Throwable e) {
    log.log(FQCN, Level.ERROR, s, e);
  }
 

其他日志適配器類也一樣,繼承"org.apache.ibatis.logging.Log"類靶草,里面持有對(duì)第三方日志框架的日志記錄類的引用

  • 客戶端即加載 LogFactory類的時(shí)候蹄胰,首先會(huì)去根據(jù)配置文件動(dòng)態(tài)確定使用哪個(gè)第三方日志框架
 <settings>
        <setting name="logImpl" value="LOG4J" />
    </settings>

解析xml配置文件的構(gòu)造器代碼截取

  Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
  configuration.setLogImpl(logImpl);

logfactory日志工廠構(gòu)造獲取具體的日志實(shí)現(xiàn)類


public final class LogFactory 
  public static final String MARKER = "MYBATIS";

  private static Constructor<? extends Log> logConstructor;

  static {
    tryImplementation(new Runnable() {
      @Override
      public void run() {
        useSlf4jLogging();
      }
    });
    tryImplementation(new Runnable() {
      @Override
      public void run() {
        useCommonsLogging();
      }
    });
    
    tryImplementation(new Runnable() {
      @Override
      public void run() {
        useLog4JLogging();
      }
    });
  .....等等
 
private static void setImplementation(Class<? extends Log> implClass) {
    try {
      Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
      Log log = candidate.newInstance(LogFactory.class.getName());
     
      }
      logConstructor = candidate;
    } catch (Throwable t) {
    
    }
  }

mybatis沒有自己的日志系統(tǒng),依賴于第三方實(shí)現(xiàn)奕翔,通過配置文件參數(shù)根據(jù)logfactory來適配對(duì)應(yīng)的第三方日志系統(tǒng)(log4j,jdk-log,commonslogging)過程略裕寨,可參照slf4j日志適配模式


代理模式

為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問,可能是框架源碼使用頻率最高的設(shè)計(jì)模式派继!

  • 應(yīng)用場(chǎng)景:rpc框架客戶端(httpinvoker/hessian/rmi)宾袜,Aop,攔截器驾窟,mybatis動(dòng)態(tài)生成mapper接口實(shí)現(xiàn)類庆猫,事務(wù)、連接池框架

  • 靜態(tài)代理

  • 動(dòng)態(tài)代理(通過對(duì)象反射動(dòng)態(tài)生成代理類 jdk/cglib/asm/javassist)

實(shí)際應(yīng)用以動(dòng)態(tài)代理居多绅络!動(dòng)態(tài)代理本質(zhì)上也是靜態(tài)代理月培,只不過是以字節(jié)碼增強(qiáng)嘁字,類加載器根據(jù)目標(biāo)target類二進(jìn)制文件,動(dòng)態(tài)生成其代理代碼杉畜,并載入jvm方法區(qū)纪蜒,類名多以xxx$xxxx.class

  • UML類圖


  • 協(xié)調(diào)調(diào)用者和被調(diào)用者,在一定程度上降低了系統(tǒng)的耦合度

應(yīng)用場(chǎng)景1

dubbo-consumer
  • 解析dubbo自定義標(biāo)簽
<dubbo:reference id="remoteService"interface="com.xxx.remoteService"/>
public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    public void init() {
        //服務(wù)消費(fèi)者標(biāo)簽bean
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        //服務(wù)提供者標(biāo)簽bean
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
      
    }
/**
 * ReferenceFactoryBean
 * 
 * @author william.liangf  duubo作者 梁飛
 * @export
   解析dubbo自定義標(biāo)簽 實(shí)現(xiàn)了InitializingBean
   初始化標(biāo)簽信息的時(shí)候此叠,向注冊(cè)中心訂閱服務(wù)纯续,并生成consumer接口的動(dòng)態(tài)代理類
 */
public class ReferenceBean<T> extends ReferenceConfig<T> implements  InitializingBean,x,x,x {
  public void afterPropertiesSet() throws Exception {
        //todo....... 
     createProxy()       
 }
private T createProxy(Map<String, String> map) {
        //todo.....
     return (T) proxyFactory.getProxy(invoker);  
 }
  • dubbo動(dòng)態(tài)代理工廠基于SPI思想,默認(rèn)由"javassist"實(shí)現(xiàn)灭袁,
    關(guān)于 SPI插件機(jī)制我有空再給大家做個(gè)技術(shù)分享專題
/**
 * ProxyFactory. (API/SPI, Singleton, ThreadSafe)
 * 
 * @author william.liangf
 */
@SPI("javassist")
public interface ProxyFactory {
  • 生成動(dòng)態(tài)代理的實(shí)現(xiàn)類
    1杆烁、jdk動(dòng)態(tài)代理
    2、javassist



    消費(fèi)端遠(yuǎn)程調(diào)用dubbo接口简卧,客戶端執(zhí)行類實(shí)際上是其代理類兔魂。
    dubbo 為這一類公共rpc接口客戶端生成動(dòng)態(tài)代理,契合面向切面編程的思想

基于netty的rpc框架實(shí)現(xiàn)是國(guó)慶節(jié)的作業(yè)举娩,大家應(yīng)該都比較熟悉了析校,dubbo的consumer類似,這里細(xì)節(jié)不再鋪開铜涉。


三克油

23種設(shè)計(jì)模式?jīng)]有結(jié)束智玻,同學(xué)們還需要繼續(xù)努力添磚加瓦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芙代,一起剝皮案震驚了整個(gè)濱河市吊奢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纹烹,老刑警劉巖页滚,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铺呵,居然都是意外死亡裹驰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門片挂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來幻林,“玉大人,你說我怎么就攤上這事音念』龋” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵闷愤,是天一觀的道長(zhǎng)整葡。 經(jīng)常有香客問我,道長(zhǎng)肝谭,這世上最難降的妖魔是什么掘宪? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮攘烛,結(jié)果婚禮上魏滚,老公的妹妹穿的比我還像新娘。我一直安慰自己坟漱,他們只是感情好鼠次,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芋齿,像睡著了一般腥寇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上觅捆,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天赦役,我揣著相機(jī)與錄音,去河邊找鬼栅炒。 笑死掂摔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赢赊。 我是一名探鬼主播乙漓,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼释移!你這毒婦竟也來了叭披?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤玩讳,失蹤者是張志新(化名)和其女友劉穎涩蜘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體熏纯,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡皱坛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了豆巨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剩辟。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖往扔,靈堂內(nèi)的尸體忽然破棺而出贩猎,到底是詐尸還是另有隱情,我是刑警寧澤萍膛,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布吭服,位于F島的核電站,受9級(jí)特大地震影響蝗罗,放射性物質(zhì)發(fā)生泄漏艇棕。R本人自食惡果不足惜蝌戒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沼琉。 院中可真熱鬧北苟,春花似錦、人聲如沸打瘪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)闺骚。三九已至彩扔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間僻爽,已是汗流浹背虫碉。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胸梆,地道東北人蔗衡。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乳绕,于是被迫代替她去往敵國(guó)和親绞惦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 本文首發(fā)于個(gè)人博客:Lam's Blog - 談?wù)?3種設(shè)計(jì)模式在Android源碼及項(xiàng)目中的應(yīng)用洋措,文章由Mark...
    格子林ll閱讀 4,628評(píng)論 1 105
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理济蝉,服務(wù)發(fā)現(xiàn),斷路器菠发,智...
    卡卡羅2017閱讀 134,600評(píng)論 18 139
  • 我不等你了滓鸠,等太多年了雁乡,等不來你那沒能兌現(xiàn)的諾言,你也實(shí)現(xiàn)不了糜俗,再見了踱稍。
    若芊閱讀 233評(píng)論 0 1
  • 前一晚便定好,我等他踢完球悠抹,喝茶吃飯珠月。 選定在達(dá)德喝茶,倒是個(gè)鬧中取靜的好地方楔敌,雪芽的茶具兩人都喜歡啤挎。 突然問到我...
    王炯炯閱讀 389評(píng)論 0 0
  • 青琉昇閱讀 173評(píng)論 0 0