介紹 Spring Integration是Spring公司的一套ESB框架。 前面ESB介紹中我也做了一定了解。我們來看一下它主要做什么的。 Spring Integration is motivated by the following goals:- Provide a simple model for implementing complex enterprise integration solutions.(暫時相信它吧,誰讓它搞個Spring框架,的確給人方便一把。)
- Facilitate asynchronous, message-driven behavior within a Spring-based application.(這個不談,Spring框架就是它玩的。再說這一點與它競爭只有Mule啦。)
- Promote intuitive, incremental adoption for existing Spring users. (也暫時相信它,別人都只說給用戶提升。)
Spring Integration is guided by the following principles:- Components should be loosely coupled for modularity and testability.(松耦合,好像很早很早就聽說過。像做夢一樣)
- The framework should enforce separation of concerns between business logic and integration logic.(分開程度要取決業(yè)務(wù)吧。)
- Extension points should be abstract in nature but within well-defined boundaries to promote reuse and portability.(美妙現(xiàn)實世界產(chǎn)品)
源碼下載打開它的網(wǎng)頁,http://www./spring-integration 主頁上也沒有東東,但有個下源代碼的地方,svn開工啦。 svn co https://src./svn/spring-integration/trunk springintegration
下載完后,進(jìn)入build-spring-integration目錄執(zhí)行ant.完成后,導(dǎo)入到Eclipse中。 導(dǎo)入項目會有很多,先添加時會有報錯。這里需要添加一個變量。 IVY_CACHE=<checkout-dir>/ivy-cache/repository
這里要注意的事,也是我遇到問題。執(zhí)行ant時,他會去下載lvy,如果你本身在%ANT_HOME%\lib里有l(wèi)vy.jar包,由于我暫時找不到如何處理,我就直接將Ant中的jar刪除掉后就沒有問題。 另外在ant過程中,測試步驟可能會在file模塊中出現(xiàn)問題,可以將相關(guān)test類中代碼注釋掉。
HelloWorld源碼分析在samples項目中,打開helloworld包里面有三個文件。 - package org.springframework.integration.samples.helloworld;
-
-
-
-
- public class HelloService {
-
- public String sayHello(String name) {
- return "Hello " + name;
- }
-
- }
package org.springframework.integration.samples.helloworld;
/**
* @author Mark Fisher
*/
public class HelloService {
public String sayHello(String name) {
return "Hello " + name;
}
}
helloworldDemo.xml - <?xml version="1.0" encoding="UTF-8"?>
- <beans:beans xmlns="http://www./schema/integration"
- xmlns:xsi="http://www./2001/XMLSchema-instance"
- xmlns:beans="http://www./schema/beans"
- xsi:schemaLocation="http://www./schema/beans
- http://www./schema/beans/spring-beans-2.5.xsd
- http://www./schema/integration
- http://www./schema/integration/spring-integration-1.0.xsd">
-
- <channel id="inputChannel"/>
-
- <channel id="outputChannel">
- <queue capacity="10"/>
- </channel>
-
- <service-activator input-channel="inputChannel"
- output-channel="outputChannel"
- ref="helloService"
- method="sayHello"/>
-
- <beans:bean id="helloService" class="org.springframework.integration.samples.helloworld.HelloService"/>
- </beans:beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www./schema/integration"
xmlns:xsi="http://www./2001/XMLSchema-instance"
xmlns:beans="http://www./schema/beans"
xsi:schemaLocation="http://www./schema/beans
http://www./schema/beans/spring-beans-2.5.xsd
http://www./schema/integration
http://www./schema/integration/spring-integration-1.0.xsd">
<channel id="inputChannel"/>
<channel id="outputChannel">
<queue capacity="10"/>
</channel>
<service-activator input-channel="inputChannel"
output-channel="outputChannel"
ref="helloService"
method="sayHello"/>
<beans:bean id="helloService" class="org.springframework.integration.samples.helloworld.HelloService"/>
</beans:beans>
HelloWorldDemo.java - package org.springframework.integration.samples.helloworld;
-
- import org.springframework.context.support.AbstractApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.integration.channel.BeanFactoryChannelResolver;
- import org.springframework.integration.channel.ChannelResolver;
- import org.springframework.integration.channel.PollableChannel;
- import org.springframework.integration.core.MessageChannel;
- import org.springframework.integration.message.StringMessage;
-
-
-
-
-
-
- public class HelloWorldDemo {
-
- public static void main(String[] args) {
- AbstractApplicationContext context = new ClassPathXmlApplicationContext("helloWorldDemo.xml", HelloWorldDemo.class);
- ChannelResolver channelResolver = new BeanFactoryChannelResolver(context);
- MessageChannel inputChannel = channelResolver.resolveChannelName("inputChannel");
- PollableChannel outputChannel = (PollableChannel) channelResolver.resolveChannelName("outputChannel");
- inputChannel.send(new StringMessage("World"));
- System.out.println(outputChannel.receive(0).getPayload());
- context.stop();
- }
-
- }
package org.springframework.integration.samples.helloworld;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.BeanFactoryChannelResolver;
import org.springframework.integration.channel.ChannelResolver;
import org.springframework.integration.channel.PollableChannel;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.message.StringMessage;
/**
* Demonstrates a basic message endpoint.
*
* @author Mark Fisher
*/
public class HelloWorldDemo {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("helloWorldDemo.xml", HelloWorldDemo.class);
ChannelResolver channelResolver = new BeanFactoryChannelResolver(context);
MessageChannel inputChannel = channelResolver.resolveChannelName("inputChannel");
PollableChannel outputChannel = (PollableChannel) channelResolver.resolveChannelName("outputChannel");
inputChannel.send(new StringMessage("World"));
System.out.println(outputChannel.receive(0).getPayload());
context.stop();
}
} Cafe源碼分析 Cafe示例描述的是星巴克的訂單處理故事。 其示例描述在:http://www./ramblings/18_starbucks.html 這里簡單描述一下,以免大家看英文太累 文章講在星巴克喝咖啡時,收銀員可能只有一個,而沖咖啡員工會有多個,如何讓收銀員產(chǎn)生訂單異步發(fā)送給沖咖啡員工。并且沖咖啡員工可能是競爭上崗的,就當(dāng)他們是計件工吧。 這里要考慮問題: 1,沖咖啡員工使用不同設(shè)備,不同咖啡沖調(diào)時間可能不同?!?nbsp; 2,沖咖啡員工可能會將相同類型的咖啡同時一起沖調(diào)。 星巴克如何處理這個問題? 就當(dāng)他解決了這個問題,它是如何把每個咖啡又送回給每個客戶呢?當(dāng)然,星巴克采用“標(biāo)識關(guān)系模式”,將每個咖啡杯上標(biāo)上名稱,并通過叫喊方式。 但并不是每天都是美好的,總有出錯的時候。例如,收銀員無法支付?沖調(diào)一杯你不喜歡的咖啡,你要換一杯?沖咖啡的設(shè)備壞了,星巴克要退你錢...這些異常情況如何處理。 因此就會有以下三種方式異常處理: 1,關(guān)閉交易,什么都不做。 2,重做,重新發(fā)起行為。 3,修正行為,相當(dāng)于退錢這種行為。 因此,這里這篇文章后面討論一下兩階段提交為什么不適合星巴克,如果你讓收銀員、沖咖啡員工,買單的人需要在一個“事務(wù)”中,交易所有完成后,再進(jìn)行下一個業(yè)務(wù)。估計星巴克會馬上倒閉啦。因此星巴克采用“Conversation pattern”模式。
好啦,業(yè)務(wù)了解清楚,我們再來看一下完整XML文件。在這里我沒有采用示例詳細(xì)的xml方式,而沒有采用annotation方式。 以下是參考文檔中的示例描述圖:
CafeDemo代碼創(chuàng)建了訂單。這家咖啡店有兩種飲料,一種是熱的,一種是冷的,消息將這訂單包裝到一個"orders"的channel(頻道)。一個endpoint偵聽到訂單頻道并根據(jù)訂單情況進(jìn)行分開處理。
完成分開處理后,程序交給DrinksRouter經(jīng)過drink頻道。而DrinkRouter一個職責(zé)就是將訂單內(nèi)容中的熱咖啡和冷咖啡交給不同的channel處理。
- <gateway id="cafe" service-interface="org.springframework.integration.samples.cafe.Cafe"/>
<gateway id="cafe" service-interface="org.springframework.integration.samples.cafe.Cafe"/>
這里Gateway主要是根據(jù)接口生成代理類。
- Cafe cafe = (Cafe) context.getBean("cafe");
- DrinkOrder order = new DrinkOrder();
- Drink hotDoubleLatte = new Drink(DrinkType.LATTE, 2, false);
- Drink icedTripleMocha = new Drink(DrinkType.MOCHA, 3, true);
- order.addDrink(hotDoubleLatte);
- order.addDrink(icedTripleMocha);
- for (int i = 0; i < 100; i++) {
- cafe.placeOrder(order);
- }
Cafe cafe = (Cafe) context.getBean("cafe");
DrinkOrder order = new DrinkOrder();
Drink hotDoubleLatte = new Drink(DrinkType.LATTE, 2, false);
Drink icedTripleMocha = new Drink(DrinkType.MOCHA, 3, true);
order.addDrink(hotDoubleLatte);
order.addDrink(icedTripleMocha);
for (int i = 0; i < 100; i++) {
cafe.placeOrder(order);
}
- @MessageEndpoint(input="orders", output="drinks")
- public class OrderSplitter {
-
- @Splitter
- public List<Drink> split(Message<DrinkOrder> orderMessage) {
- return orderMessage.getPayload().getDrinks();
- }
-
- }
@MessageEndpoint(input="orders", output="drinks")
public class OrderSplitter {
@Splitter
public List<Drink> split(Message<DrinkOrder> orderMessage) {
return orderMessage.getPayload().getDrinks();
}
}
- @MessageEndpoint(input="drinks")
- public class DrinkRouter {
-
- @Router
- public String resolveDrinkChannel(Drink drink) {
- return (drink.isIced()) ? "coldDrinks" : "hotDrinks";
- }
-
- }
@MessageEndpoint(input="drinks")
public class DrinkRouter {
@Router
public String resolveDrinkChannel(Drink drink) {
return (drink.isIced()) ? "coldDrinks" : "hotDrinks";
}
}
- <handler-endpoint handler="coldBarista" input-channel="coldDrinks"
- method="prepareColdDrink">
- </handler-endpoint>
-
- <handler-endpoint handler="hotBarista" input-channel="hotDrinks"
- method="prepareHotDrink">
- </handler-endpoint>
<handler-endpoint handler="coldBarista" input-channel="coldDrinks"
method="prepareColdDrink">
</handler-endpoint>
<handler-endpoint handler="hotBarista" input-channel="hotDrinks"
method="prepareHotDrink">
</handler-endpoint>
- public void prepareColdDrink(Message<Drink> drinkMessage) {
- Drink drink = drinkMessage.getPayload();
-
- }
|