AliKevin 写道
本系列文章不涉及过多的S4的理论内容,因为s4论文中描述相当清楚(我认为我实在是说的不会比论文中更清楚了:)呵呵),论文信息请看论文 http://dl.iteye.com/topics/download/704e5924-0dd8-34df-b44f-2efbc91de071
S4现有框架的应用开发十分方便,我们只需要实现标准接口,配置定制应用的spirng配置问题就,利用Spring的注入方式将你的应用集成到S4框架中。
所以我可以任何方式建立java工程,形成jar包和配置文档部署到s4的apps下面,但为了和s4统一开发方式我们还是推荐用gradle构建应用项目.
一、销售监控的示例场景描述
销售监控的示例的应用场景是:假设我们关注所有产品的销售情况,我们监控所有产品的销售事件,当有产品售出的时候会产生一个Sell的事件流,事件流中包含产品的名称和销售数量,当销售数量大于10000时候,我们会触发另一个事件流Celebrate的事件,通知文艺团队进行庆祝演出准备(当然是假设,没有什么节目可以看哦:))。事件流的处理我们只是在控制台输出信息。
二、建立gradle的目录结构
root@slave:/kevin/sellMoniter# cd /kevin root@slave:/kevin# mkdir sellMoniter root@slave:/kevin# cd sellMoniter/ root@slave:/kevin/sellMoniter# mkdir -p src/main/resources root@slave:/kevin/sellMoniter# mkdir src/main/java root@slave:/kevin/sellMoniter# vi build.gradle
build.gradle内容如下:
/* * Copyright (c) 2011 Yahoo! Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. See accompanying LICENSE file. */ /* * Twitter Topic Count Application Build Script * * Modify this script to create a build script for your app. * * NOTE: You must set up the environment variable S4_IMAGE before * running this script. * * Tasks: * * gradlew TASK1, TASK2, ... (or gradle TASK1, ... if gradle is installed.) * * build - builds the application * install - creates scripts to run applications * deploy - deploys the S4 app to the S4 image * clean - cleans build dir and removes app from S4 image * eclipse - creates an project for the Eclipse IDE */ /* Set a version number for your app. */ version = new Version(major: 0, minor: 1, bugfix: 0) group = 'alibaba.com' /* Read S4_IMAGE environment variable. */ env = System.getenv() s4Image = env['S4_IMAGE'] if (s4Image == null) { logger.warn("\nEnvironment variable S4_IMAGE not set.") System.exit(-1) } /* Search these repos to find artifacts. Gradle will download and cache. */ repositories { flatDir name: 's4core', dirs: "${s4Image}/s4-core/lib" flatDir name: 's4driver', dirs: "${s4Image}/s4-driver/lib" mavenLocal() mavenCentral() } /* Include handy Gradle plugins. */ apply plugin: 'eclipse' apply plugin: 'java' apply plugin: "application" /* Set Java version. */ sourceCompatibility = 1.6 targetCompatibility = 1.6 /* Main application to run ... */ mainClassName = "com.alibaba.s4.SellMachine" applicationName = "sellMachine" /* Dependencies. */ dependencies { compile('io.s4:s4-core:0.3.0' ) compile('io.s4:s4-driver:0.3.0' ) compile('org.json:json:20090211' ) compile('com.google.code.gson:gson:1.6' ) compile('log4j:log4j:1.2.15' ) compile('commons-cli:commons-cli:1.2' ) compile('commons-logging:commons-logging:1.1.1' ) compile('commons-io:commons-io:2.0.1' ) testCompile('junit:junit:4.4' ) } /* Customize your jar files. */ manifest.mainAttributes( provider: 'gradle', 'Implementation-Url': 'http://www.cn.alibaba-inc.com', 'Implementation-Version': version, 'Implementation-Vendor': 'The S4-SellMoniter Project', 'Implementation-Vendor-Id': 'alibaba.com' ) /* Bug workaround. */ eclipseClasspath { downloadSources = false; // required for eclipseClasspath to work } /* Create an inage to copy and archive your app. */ deployImage = copySpec { into ("s4-apps/" + project.name + "/lib") { from project.configurations.runtime from project.configurations.archives.allArtifactFiles } into ("s4-apps/" + project.name) { from project.sourceSets.main.resources } } /* Copy to the S4 Image. */ task deploy(type: Copy) { description = "Copy app files to deployment dir." destinationDir = file(s4Image) with deployImage } /* Add remove app to the clean task. */ task cleanDeployment(type: Delete) { delete("${s4Image}/s4-apps/${project.name}") } clean.dependsOn cleanDeployment /* Generates the gradlew scripts. http://www.gradle.org/1.0-milestone-3/docs/userguide/gradle_wrapper.html */ task wrapper(type: Wrapper) { gradleVersion = '1.0-milestone-3' } class Version { int major int minor int bugfix String releaseType String toString() { "$major.$minor.$bugfix${releaseType ? '-'+releaseType : ''}" } }
三、生成eclipse工程
为了我们快速开发,我完成grade的目录机构后我们利用gradle命令生成eliplse工程:
root@slave:/kevin/sellMoniter# gradle eclipse :eclipseClasspath Download file:/root/.m2/repository/junit/junit/4.4/junit-4.4.pom Download file:/root/.m2/repository/junit/junit/4.4/junit-4.4.jar :eclipseJdt :eclipseProject :eclipse BUILD SUCCESSFUL Total time: 8.719 secs root@slave:/kevin/sellMoniter#
四、用eclipse中开发相关的类见附件【sellMoniter.rar】
a.事件对象类Sell.java
/** * Project: sellMoniter * * File Created at 2011-10-17 * $Id$ * * Copyright 1999-2100 Alibaba.com Corporation Limited. * All rights reserved. * * This software is the confidential and proprietary information of * Alibaba Company. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Alibaba.com. */ package com.alibaba.s4; /** * TODO Comment of Sell * * @author jincheng.sunjc */ public class Sell { private String sellInfo; //format productName:count,notebook:5 /** * @return the sellInfo */ public String getSellInfo() { return sellInfo; } /** * @param sellInfo the sellInfo to set */ public void setSellInfo(String sellInfo) { this.sellInfo = sellInfo; } @Override public String toString() { String[] info = this.sellInfo.split(":"); return "[We had sell " + info[1] + " " + info[0] + " ! :)]"; } public String getName() { return this.sellInfo.split(":")[0]; } public int getCount() { return Integer.parseInt(this.sellInfo.split(":")[1].trim()); } public static void main(String[] args) { Sell s = new Sell(); s.setSellInfo("notebook:5"); System.out.println(s.toString()); System.out.println(s.getCount()); System.out.println(s.getName()); } }
b.事件对象类Celebrate.java
/** * Project: sellMoniter * * File Created at 2011-10-17 * $Id$ * * Copyright 1999-2100 Alibaba.com Corporation Limited. * All rights reserved. * * This software is the confidential and proprietary information of * Alibaba Company. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Alibaba.com. */ package com.alibaba.s4; /** * TODO Comment of Celebrate * * @author jincheng.sunjc */ public class Celebrate { private String celebrateInfo; /** * @return the celebrateInfo */ public String getCelebrateInfo() { return celebrateInfo; } /** * @param celebrateInfo the celebrateInfo to set */ public void setCelebrateInfo(String celebrateInfo) { this.celebrateInfo = celebrateInfo; } public String getCelebrate() { return "1"; } public void setCelebrate(String id) { // do nothing } @Override public String toString() { return this.celebrateInfo; } }
c.Sell事件流处理类SellPE.java
/**
* Project: sellMoniter
*
* File Created at 2011-10-17
* $Id$
*
* Copyright 1999-2100 Alibaba.com Corporation Limited.
* All rights reserved.
*
* This software is the confidential and proprietary information of
* Alibaba Company. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Alibaba.com.
*/
package com.alibaba.s4;
import io.s4.dispatcher.Dispatcher;
import io.s4.processor.AbstractPE;
/**
* TODO Comment of SellPE
*
* @author jincheng.sunjc
*/
public class SellPE extends AbstractPE {
/**
* Dispatcher that will dispatch events on Sentence *
stream.
*/
private Dispatcher dispatcher;
public Dispatcher getDispatcher() {
return dispatcher;
}
public void setDispatcher(Dispatcher dispatcher) {
this.dispatcher = dispatcher;
}
public void processEvent(Sell sell) {
System.out.println("Received: " + sell);
if (sell.getCount() > 10000) {
System.out.print("well done we need a celebrate...");
Celebrate c = new Celebrate();
c.setCelebrateInfo("Hi,Because " + sell + " ,So we must have a celebration meeting....");
// dispatch a Sentence event
dispatcher.dispatchEvent("Celebrate", c);
}
}
@Override
public void output() {
// TODO Auto-generated method stub
}
@Override
public String getId() {
return this.getClass().getName();
}
}
d.Celebrate事件流处理类CelebratePE.java
/** * Project: sellMoniter * * File Created at 2011-10-17 * $Id$ * * Copyright 1999-2100 Alibaba.com Corporation Limited. * All rights reserved. * * This software is the confidential and proprietary information of * Alibaba Company. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Alibaba.com. */ package com.alibaba.s4; import io.s4.processor.AbstractPE; /** * TODO Comment of SellPE * * @author jincheng.sunjc */ public class CelebratePE extends AbstractPE { public void processEvent(Celebrate celebrate) { System.out.println("Received: " + celebrate.getCelebrateInfo()); } @Override public void output() { // TODO Auto-generated method stub } @Override public String getId() { return this.getClass().getName(); } }
e.Spring配置文件sellMoniter-conf.xml
Sell *
Celebrate *
Celebrate
celebrate
f.客户端测试类SellMachine.java
/** * Project: sellMoniter * * File Created at 2011-10-17 * $Id$ * * Copyright 1999-2100 Alibaba.com Corporation Limited. * All rights reserved. * * This software is the confidential and proprietary information of * Alibaba Company. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Alibaba.com. */ package com.alibaba.s4; import io.s4.client.Driver; import io.s4.client.Message; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; /** * TODO Comment of SellMachine * * @author jincheng.sunjc */ public class SellMachine { public static void main(String[] args) { String hostName = "localhost"; hostName = "192.168.254.129"; int port = 2334; String streamName = "Sell"; String clazz = "com.alibaba.s4.Sell"; Driver d = new Driver(hostName, port); Reader inputReader = null; BufferedReader br = null; try { if (!d.init()) { System.err.println("Driver initialization failed"); System.exit(1); } if (!d.connect()) { System.err.println("Driver initialization failed"); System.exit(1); } inputReader = new InputStreamReader(System.in); br = new BufferedReader(inputReader); for (String inputLine = null; (inputLine = br.readLine()) != null;) { String sellInfo = "{\"sellInfo\":\"" + inputLine + "\"}"; System.out.println("sellInfo-> " + sellInfo); Message m = new Message(streamName, clazz, sellInfo); d.send(m); } } catch (IOException e) { e.printStackTrace(); } finally { try { d.disconnect(); } catch (Exception e) { } try { br.close(); } catch (Exception e) { } try { inputReader.close(); } catch (Exception e) { } } } }
OK,这些简单的代码已经足以完成我们的业务场景的需求了:)。
五、部署sellMoniter
root@slave:/kevin/s4/build/s4-image# rm -fr $S4_IMAGE/s4-apps/* root@slave:/kevin/s4/build/s4-image# rm $S4_IMAGE/s4-core/logs/s4-core/* root@slave:/kevin/s4/build/s4-image# rm $S4_IMAGE/s4-core/lock/* root@slave:cd /kevin/sellMoniter root@slave:/kevin/sellMoniter# :/kevin/sellMoniter# gradle install :compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :jar UP-TO-DATE :startScripts UP-TO-DATE :installApp BUILD SUCCESSFUL Total time: 7.258 secs root@slave:/kevin/sellMoniter# gradle deploy :compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :jar UP-TO-DATE :deploy BUILD SUCCESSFUL Total time: 6.81 secs
这样我们将我们开发的应用部署到s4中了,可以进行运行测试了:)
六、启动s4服务和adapetr服务
$S4_IMAGE/scripts/start-s4.sh -r client-adapter appName=s4 dequeuer number: 6 [] [/kevin/s4/build/s4-image/s4-apps/sellMoniter/sellMoniter-conf.xml] Adding processing element with bean name sellCatcher, id com.alibaba.s4.SellPE adding pe: com.alibaba.s4.SellPE@14d5bc9 Using ConMapPersister .. Adding processing element with bean name celebrateCatcher, id com.alibaba.s4.CelebratePE adding pe: com.alibaba.s4.CelebratePE@1202d69 Using ConMapPersister ..
如上信息说明我们部署了sellMoniter应用,并加载了sellMoniter-conf.xml配置文件,
root@slave:/kevin/s4# $S4_IMAGE/scripts/run-client-adapter.sh -s client-adapte-g s4 -d $S4_IMAGE/s4-core/conf/default/client-stub-conf.xml .client.Adapter -t default -c /kevin/s4/build/s4-image/s4-core -d /kevin/s4/build/s4-image/s4-core/conf/default/client-stub-conf.xml appName=client-adapter dequeuer number: 12 Adding InputStub genericStub Adding OutputStub genericStub
如上说明adapter已经启动。
七、启动测试类,并查看s4服务端信息
a.客户端
root@slave:/kevin/sellMoniter/build/install/sellMachine/bin# ./sellMachine iphone:500 sellInfo-> {"sellInfo":"iphone:500"} iphone:50000 sellInfo-> {"sellInfo":"iphone:50000"}
b.s4服务端
Received: [We had sell 500 iphone ! :)] Received: [We had sell 50000 iphone ! :)] well done we need a celebrate...{ java.lang.String celebrateInfo java.lang.String celebrate } Using fast path! Value 1, partition id 0 Received: Hi,Because [We had sell 50000 iphone ! :)] ,So we must have a celebration meeting....
如上信息证明当我们销售5个iphone的时候我们只是处理的一个sell的事件流,当我们的产品销售数量超过10000的时候我们就要触发一个celebrate的事件流,进行庆祝通知。:)
好了,到此我们针对S4的客户定制开发的例子也开发完毕了,让我们小小的庆祝一下吧:)Cheers\!