2019独角兽企业重金招聘Python工程师标准>>>
首先,我们下载zookeeper-3.3.6.tar.gz,最好不要最新版本,新版本在jdk1.5下有问题。解压后在
zookeeper-3.3.6/contrib/fatjar目录下有一个zookeeper-3.3.6-fatjar.jar文件,我们用这个jar来写。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class ZKServerStart {
/**
* 启动zookeeper服务
* @param zoocfg zoo.cfg文件的物理路径
* @param zooDataDir zookeeper的data路径
* @throws Exception
*/
public static void Run(String zoocfg, String zooDataDir) throws Exception {
//加载zoocfg配置文件
Properties prop = loadProperties(zoocfg);
//提取本机服务的server编号,这个my.id是默认的zoo.cfg里没有的,需要我们后加上,
//它的值就是当前节点的serverNum
String serverNum = prop.getProperty("my.id");
//提取zookeeper的客户端IP和端口,把IP和端口提取出来,方便我们的客户端API使用
Global.zkClientIp = prop.getProperty("server." + serverNum).split(":")[0];
Global.zkClientPort = Integer.parseInt(prop.getProperty("clientPort"));
//myid文件的路径
String dataDir = zooDataDir + "/ZooData";
//写入myid文件
writeMyid(dataDir, serverNum);
prop.setProperty("dataDir", dataDir);
//将dataDir保存到zoo.cfg
saveConfig(prop, zoocfg);
String[] config = {zoocfg};
Class> clazz = Class.forName("org.apache.zookeeper.server.quorum.QuorumPeerMain");
Method main = clazz.getMethod("main", String[].class);
//启动zookeeper
main.invoke(null, (Object)config);
}
/*
* 保存zookeeper的配置文件
*/
private static void saveConfig(Properties prop, String configFile) throws IOException {
OutputStream out = new FileOutputStream(configFile);
try{
prop.store(out, null);
} finally {
if(out != null) out.close();
}
}
/*
* 将server的编号写入myid文件
*/
private static void writeMyid(String dataDir, String serverNum)
throws IOException, FileNotFoundException {
File dir = new File(dataDir);
if(!dir.exists()) dir.mkdirs();
File myid = new File(dataDir + "/myid");
if(!myid.exists()) myid.createNewFile();
OutputStream out = new FileOutputStream(myid);
try{
out.write(serverNum.getBytes());
} finally {
if(out != null) out.close();
}
}
/*
* 加载zoocfg配置
*/
private static Properties loadProperties(String zoocfg) throws FileNotFoundException, IOException {
Properties prop = new Properties();
InputStream is = new FileInputStream(zoocfg);
try{
prop.load(is);
} finally {
if(is != null) is.close();
}
return prop;
}
}
注意,使用这个启动类来启动zookeeper的时候要放到线程中。例如,我们在Servlet的init()方法中启动:
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
public class ZooServlet extends HttpServlet{
@Override
public void init() throws ServletException {
String zooConfig = this.getInitParameter("ZooConfig");
//找到WEB-INF的物理路径
final String webInfo = getWebInfPath();
//找到zoo.cfg的物理路径
final String configPath = webInfo + zooConfig.substring(1, zooConfig.length());
new Thread(new Runnable(){
public void run() {
//启动zookeeper服务
try {
ZKServerStart.Run(configPath, webInfo);
} catch (Exception e) {
e.printStackTrace();
}
}}).start();
super.init();
}
private String getWebInfPath() {
URL url = this.getClass().getProtectionDomain().getCodeSource().getLocation();
String path = url.toString();
int index = path.indexOf("WEB-INF");
if (index == -1) {
index = path.indexOf("classes");
}
if (index == -1) {
index = path.indexOf("bin");
}
path = path.substring(0, index);
if (path.startsWith("zip")) {// 当class文件在war中时,此时返回zip:D:/...这样的路径
path = path.substring(4);
} else if (path.startsWith("file")) {// 当class文件在class文件中时,此时返回file:/D:/...这样的路径
path = path.substring(6);
} else if (path.startsWith("jar")) {// 当class文件在jar文件里面时,此时返回jar:file:/D:/...这样的路径
path = path.substring(10);
}
try {
path = URLDecoder.decode(path, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return path;
}
}
web.xml的配置:
ZooServlet
ZooServlet
ZooConfig
/WEB-INF/conf/zoo.cfg
1
ZooServlet
*.do
index.jsp
这样,Servlet在初始化的时候就启动了zookeeper,同时将zookeeper的dataDir目录设置到WEB-INF/ZooData/下。同时我们还提取了zookeeper的当前节点的IP和客户端端口,方便在调用客户端API的地方使用。
最后看一下zoo.cfg配置
tickTime=2000
initLimit=10
syncLimit=5
dataDir=
clientPort=2181
server.1=192.168.1.1:2888:3888
server.2=192.168.1.2:2888:3888
server.3=192.168.1.3:2888:3888
my.id=1
这个my.id是后加的一个属性,用于记录当前节点的server编号,方便我们写入到myid文件中。