JStorm與Storm源碼分析(七)--BasicBoltExecutor與裝飾模式
在Storm中IBasicBolt的主要作用是為用戶提供一種更為簡單的Bolt編寫方式,更為簡單體現在Storm框架本身幫你處理了所發出消息的Ack、Fail和Anchor操作,而這部分操作是由執行器BasicBoltExecutor 實現的。
下面我們看一下BasicBoltExecutor的源碼:
/** * BasicBoltExecutor實現了IRichBolt接口 * 在該類中持有一個IBasicBolt成員變量用於調用轉發 * 說明: * 該類是基於裝飾模式實現的. */ public class BasicBoltExecutor implements IRichBolt { public static Logger LOG = LoggerFactory.getLogger(BasicBoltExecutor.class); //持有IBasicBolt類型的變量 private IBasicBolt _bolt; //定義了成員變量_collector private transient BasicOutputCollector _collector; public BasicBoltExecutor(IBasicBolt bolt) { _bolt = bolt; } /** * 實現declareOutputFields方法,但它實際上是 * _bolt調用declareOutputFields方法 */ public void declareOutputFields(OutputFieldsDeclarer declarer) { _bolt.declareOutputFields(declarer); } /** * 實現prepare方法, * 實際上是調用_bolt的prepare方法, * 並實例化BasicOutputCollector */ public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) { _bolt.prepare(stormConf, context); _collector = new BasicOutputCollector(collector); } /** * 實現execute方法 */ public void execute(Tuple input) { //設置運行器上下文, //它表示經execute方法發送出去的消息都是由輸入消息產生的, //即輸出的消息都將標記為輸入消息所衍生出來的消息, //這是使用IBasicBolt實現消息跟蹤的重要一環 _collector.setContext(input); try { //調用_bolt的execute方法 _bolt.execute(input, _collector); //對輸入的消息進行Ack操作. //這一步意味著基於當前輸入消息的處理和衍生消息的發送已經完成, //這時就可以對該消息進行Ack操作了. _collector.getOutputter().ack(input); } catch(FailedException e) { //Storm捕獲所有的FailedException,並對輸入的消息進行Fail操作。 //如果捕獲的異常為ReportedFailedException的實例, //則調用reportError回調方法,給用戶一個機會去處理異常 //FailedException是Storm定義的一種基本異常,用來進行消息的失敗重發等操作, //並不會導致Topology運行停止 if(e instanceof ReportedFailedException) { _collector.reportError(e); } _collector.getOutputter().fail(input); } } public void cleanup() { _bolt.cleanup(); } public Map<String, Object> getComponentConfiguration() { return _bolt.getComponentConfiguration(); } }
先說說裝飾模式的結構,裝飾模式UML類圖如圖所示:
如上圖所示,裝飾模式的角色構成:
(1)抽象組件角色-Component:給出一個抽象接口,以規範或約束準備接收附加職責的對象.
(2)具體組件對象-ConcreteComponent:實現了組件對象的接口,通常是被裝飾器裝飾的原始對象.
(3)裝飾角色-Decorator:所有裝飾器的抽象父類,需要定義一個與組件接口一致的接口,
並持有一個Component對象,其實就是持有被裝飾的對象
(4)具體裝飾對象-ConcreteDecorator:實際的裝飾器對象,負責給組件對象添加附加的功能
現在舉一個常見的例子(沖咖啡)來說明一下。
我敲代碼困了,想沖一杯咖啡來提提神,但我怕咖啡苦,便向咖啡裏加點糖(用糖裝飾一番),喝著喝著覺得沒有牛奶香,邊往咖啡裏到點牛奶(用牛奶裝飾咖啡一番),這整個過程便可看成裝飾模式.
代碼:
1.先定義一個接口用來約束職責對象
/** * Component * 抽象構建角色, * 約束或規範準備接收附加責任的對象 */ public interface Component { public void operation(); }
2.實現組件對象的接口,它是被裝飾器裝飾的原始對象(這裏是咖啡)
/** * ConcreteComponent * 接收附加責任 */ public class ConcreteComponent implements Component { @Override public void operation() { System.out.println("的咖啡"); } }
3.定義裝飾器
/** * Decorator裝飾角色 */ public abstract class Decorator implements Component { //持有一個構建對象的實例 private Component component; public Decorator(Component component){ this.component=component; } @Override public void operation() { component.operation(); } }
4.實現加糖裝飾器和加牛奶裝飾器
/** * ConcreteDecorator1 * 加糖裝飾器 */ public class ConcreteDecorator1 extends Decorator { public ConcreteDecorator1(Component component) { super(component); // TODO Auto-generated constructor stub } public void operation(){ System.out.print("加糖"); super.operation(); } }
/** * ConcreteDecorator2 * 加奶裝飾器 */ public class ConcreteDecorator2 extends Decorator { public ConcreteDecorator2(Component component) { super(component); // TODO Auto-generated constructor stub } public void operation(){ System.out.print("加奶"); super.operation(); } }
5.測試
public class Test { public static void main(String[] args) { // TODO Auto-generated method stub Component component=new ConcreteComponent(); Decorator decorator1=new ConcreteDecorator2(component); Decorator decorator2=new ConcreteDecorator1(decorator1); decorator2.operation(); } }
6.測試結果
加糖加奶的咖啡
jdk中也大量使用裝飾模式。比如Java流接口中輸出流部分
OutputStream就相當於裝飾模式中的Component;
FileOutputStream、ObjectOutputStream這幾個對象直接繼承了OutputStream,
還有一些對象直接繼承OutputStream對象,比如:ByteArrayOutputStream、PipedOutputStream等.這些對象相當於裝飾模式中的ConcreteComponent,是可以被裝飾器裝飾的對象.
FilterOutputStream相當於裝飾模式中的Decorator,而他的子類DataOutputStream、BufferedOutputStream就相當於裝飾模式中的ConcreteDecorator。FilterOutputStream和它的子類對象的構造器都是傳入組件OutputStream。對照上述將的裝飾模式的結構圖,由此可見這部分類的設計完全采用裝飾模式.
同理輸入流部分也類似。
註:內容部分為學習李明老師Storm源碼分析的筆記整理。
歡迎關註下面二維碼進行技術交流:
JStorm與Storm源碼分析(七)--BasicBoltExecutor與裝飾模式