前言
設(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類圖
一層一層嵌套,"裝飾器類" 持有目標(biāo)對(duì)象的引用尖滚,具體方法執(zhí)行委托給具體的目標(biāo)對(duì)象子類形成了一連串"裝飾器鏈"丧裁,不斷地增強(qiáng)功能
應(yīng)用場(chǎng)景1
mybatis 二級(jí)緩存
-
抽象組件實(shí)現(xiàn)類 (cache.impl包下)
裝飾器族(cache.decorators包下)
- 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類圖
- 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í)行器
- 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)系圖譜
-
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));
}
- 注釋驚見dubbo作者 梁飛
梁飛技術(shù)博客地址:http://javatar.iteye.com/
/**
* 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é)不再鋪開铜涉。