一、eclipse导出maven工程的可执行jar包
建立两个maven工程 ZKServer 和ZKClient
注意:用maven进行开发管理的话,默认的打出来的jar包是不能运行的,需要在pom.xml文件中添加如下配置以生成可执行的jar包
<build>
<plugins> <plugin> <artifactId> maven-assembly-plugin </artifactId> <configuration> <descriptorRefs> <descriptorRef>zkServer</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.fanghao.AppServer</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>而我们在eclipse中创建的工程默认的 JRE System Library 是 Java-SE-1.5 ,我们需要添加以下配置让其变成1.7或1.8,并且无论我们对该maven工程update多少次,都不会回到1.5
<build>
<plugins><plugin>
<groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin></plugins>
</build>
ZKServer工程
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.fanghao</groupId> <artifactId>ZKServer</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.11</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId> maven-assembly-plugin </artifactId> <configuration> <descriptorRefs> <descriptorRef>zkServer</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.fanghao.AppServer</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build></project>--------------------------------------------------------
package com.fanghao;
import java.util.concurrent.CountDownLatch;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooDefs.Ids;/**
* 某分布式系统中,主节点可以有多台,可以动态上下线; * 任意一台客户端都能实时感知到主节点服务器的上下线。 */public class AppServer { private String groupNode = "sgroup"; private String subNode = "sub"; private CountDownLatch latch = new CountDownLatch(1); /** * 连接zookeeper * @param address server的地址 */ public void connectZookeeper(String address) throws Exception { ZooKeeper zk = new ZooKeeper("192.168.1.100:2181", 5000, new Watcher() { public void process(WatchedEvent event) { // 不做处理 if(event.getState()==KeeperState.SyncConnected){ latch.countDown(); } } }); // 在"/sgroup"下创建子节点 // 子节点的类型设置为EPHEMERAL_SEQUENTIAL, 表明这是一个临时节点, 且在子节点的名称后面加上一串数字后缀 // 将server的地址数据关联到新创建的子节点上 latch.await(); String createdPath = zk.create("/" + groupNode + "/" + subNode, address.getBytes("utf-8"), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println("create: " + createdPath); } /** * server的工作逻辑写在这个方法中 * 此处不做任何处理, 只让server sleep */ public void handle() throws InterruptedException { Thread.sleep(Long.MAX_VALUE); } public static void main(String[] args) { // 在参数中指定server的地址 if (args.length == 0) { System.err.println("The first argument must be server address"); System.exit(1); } AppServer as = new AppServer(); try { as.connectZookeeper(args[0]); as.handle(); } catch (Exception e) { e.printStackTrace(); } } }
ZKClient工程
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.fanghao</groupId> <artifactId>ZKClient</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.11</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId> maven-assembly-plugin </artifactId> <configuration> <descriptorRefs> <descriptorRef>zkClient</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.fanghao.AppClient</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build></project>------------------------------------------------------------------
package com.fanghao;
import java.util.ArrayList;
import java.util.List;import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.Watcher.Event.EventType;import org.apache.zookeeper.data.Stat;/**
* 某分布式系统中,主节点可以有多台,可以动态上下线; * 任意一台客户端都能实时感知到主节点服务器的上下线。 * Created by tianjun on 2016/12/19 0019. */public class AppClient { private String groupNode = "sgroup"; private ZooKeeper zk; private Stat stat = new Stat(); private volatile List<String> serverList; /** * 连接zookeeper */ public void connectZookeeper() throws Exception { zk = new ZooKeeper("127.0.0.1:2181", 5000, new Watcher() { public void process(WatchedEvent event) { // 如果发生了"/sgroup"节点下的子节点变化事件, 更新server列表, 并重新注册监听 if (event.getType() == EventType.NodeChildrenChanged && ("/" + groupNode).equals(event.getPath())) { try { updateServerList(); } catch (Exception e) { e.printStackTrace(); } } } }); updateServerList(); } /** * 更新server列表 */ private void updateServerList() throws Exception { List<String> newServerList = new ArrayList<String>(); // 获取并监听groupNode的子节点变化 // watch参数为true, 表示监听子节点变化事件. // 每次都需要重新注册监听, 因为一次注册, 只能监听一次事件, 如果还想继续保持监听, 必须重新注册 List<String> subList = zk.getChildren("/" + groupNode, true); for (String subNode : subList) { // 获取每个子节点下关联的server地址 byte[] data = zk.getData("/" + groupNode + "/" + subNode, false, stat); newServerList.add(new String(data, "utf-8")); } // 替换server列表 serverList = newServerList; System.out.println("server list updated: " + serverList); } /** * client的工作逻辑写在这个方法中 * 此处不做任何处理, 只让client sleep */ public void handle() throws InterruptedException { Thread.sleep(Long.MAX_VALUE); } public static void main(String[] args) throws Exception { AppClient ac = new AppClient(); ac.connectZookeeper(); ac.handle(); }}
右键待导出的maven工程-> Export -> Java -> Runnable JAR file,单击next
注意:如果 Launch Configuration:下面没有工程对应的main方法所在的类或者什么都没有,说明该类没有在eclipse中执行过,只需要将该类执行一次即可;
如果 Launch Configuration:下面的类太多了,可以将其清空,方法为删除当前workspace对应的目录下的 .metadata\.plugins\org.eclipse.debug.core\.launches 目录下的内 容,注意是删除workspace对应的目录下的 .metadata\.plugins\org.eclipse.debug.core\.launches 目录下的内容,不是删除该目录
二、在Windows系统下执行可执行jar包
打开cmd命令行窗口,切换到导出的可执行jar包所在的目录,执行命令 java -jar xxx.jar [arg0] [arg1] [...]
其中 xxx.jar 是可执行jar包的名字,后面可传入零或多个参数
三、在Linux系统下执行可执行jar包(亦可叫做启动或停止java应用程序)
1、检查jdk是否已经安装在Ubuntu上
打开终端,使用下面的命令:java -versio
如果你看到像下面的输出,这就意味着你并没有安装过Jdk:
The program ‘java’ can be found in the following packages:*default-jre* gcj-4.6-jre-headless* openjdk-6-jre-headless* gcj-4.5-jre-headless* openjdk-7-jre-headless Try: sudo apt-get install
2、在Ubuntu上安装jdk
(1)下载jdk-8u161-linux-x64.tar.gz,直接用鼠标拖放到Ubuntu的桌面文件夹里,然后复制到在/usr/soft(如果没有请新建)目录下,解压后删除jdk-8u161-linux-x64.tar.gz
(2)配置java环境变量,配置在/etc/environment文件中
执行命令 gedit /etc/environment 打开/etc/environment文件的编辑窗口,配置JAVA_HOME,CLASSPATH和PATH,如下
JAVA_HOME="/usr/soft/jdk1.8.0_161"
CLASSPATH=".:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar"PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:$JAVA_HOME/bin:$HADOOP_INSTALL/bin"(3)保存后执行 source /etc/environment 使其立即生效,执行 java -version 命令检查配置是否成功
3、执行可执行jar包
将可执行jar包拖放到某个目录,然后切换到该目录,直接执行命令 java -jar xxx.jar [arg0] [arg1] [...]
其中 xxx.jar 是可执行jar包的名字,后面可传入零或多个参数,也可编写启动停止的shell脚本,如下是一个通用shell脚本
#!/bin/sh
#JDK所在目录
JAVA_HOME="/usr/soft/jdk1.8.0_161" #执行程序启动所使用的系统用户,考虑到安全,不推荐使用root用户RUNNING_USER=root #Java程序所在的目录(classes的上一级目录)APP_HOME=/opt/xxx/WEB-INF #需要启动的Java主程序(main方法所在类)APP_MAINCLASS=com.fanghao.Main #拼凑完整的classpath参数,包括制定lib目录下所有的jarCLASSPATH=$APP_HOME/classesfor i in "$APP_HOME"/lib/*.jar; do CLASSPATH="$CLASSPATH":"$i"done #java虚拟机启动参数JAVA_OPTS="-ms512m -mx512m -Xmn256m -Djava.awt.headless=true -XX:MaxPermSize=128m"
########################################
#(函数)判断程序是否已启动#说明:使用JDK自带的JPS命令及grep命令组合,准确查找pid# jps加l参数,表示显示java的完整包路径# 使用awk,分割出pid($1部分),及java程序名称($2部分)#########################################初始化psid变量(全局)psid=0checkpid() {
javaps=`$JAVA_HOME/bin/jps -l | grep $APP_MAINCLASS` if [ -n "$javaps" ]; then psid=`echo $javaps | awk '{print $1}'` else psid=0 fi}########################################
#(函数)启动程序#说明:#1、首先调用checkpid函数,刷新$psid全局变量#2、如果程序已经启动($psid不等于0),则提示程序已启动#3、如果程序没有被启动,则执行启动命令行#4、启动命令执行后,再次调用checkpid函数#5、如果步骤4的结果能够确认程序的pid,则打印[OK],否则打印[Failed]#注意:echo -n 表示打印字符后,不换行#注意:"nohup 某命令 >/dev/null 2>&1 &" 的用法########################################start() { checkpid if [ $psid -ne 0 ]; then echo "===============================" echo "warn: $APP_MAINCLASS already started! (pid=$psid)" echo "===============================" else echo -n "Starting $APP_MAINCLASS ..." JAVA_CMD="nohup $JAVA_HOME/bin/java $JAVA_OPTS -classpath $CLASSPATH $APP_MAINCLASS >/dev/null 2>&1 &" su - $RUNNING_USER -c "$JAVA_CMD" checkpid if [ $psid -ne 0 ]; then echo "(pid=$psid) [Successfully started]" else echo "[Failed to start]" fi fi}########################################
#(函数)停止程序#说明:#1、首先调用checkpid函数,刷新$psid全局变量#2、如果程序已经启动($psid不等于0),则开始执行停止,否则提示程序未运行#3、使用kill -9 pid命令强制杀死进程#4、执行kill命令后,马上查看上一句命令的返回值:$?#5、如果步骤4的结果$?等于0,则打印[Successfully stopped],否则打印[Failed to stop]#6、为了防止java程序被启动多次,这里增加反复检查进程,反复杀死的处理(递归调用stop)#注意:echo -n 表示打印字符后,不换行#注意:在shell编程中,"$?" 表示上一句命令或者一个函数的返回值########################################stop() { checkpid if [ $psid -ne 0 ]; then echo -n "Stopping $APP_MAINCLASS ...(pid=$psid)" su - $RUNNING_USER -c "kill -9 $psid" if [ $? -eq 0 ]; then echo "[Successfully stopped]" else echo "[Failed to stop]" fi checkpid if [ $psid -ne 0 ]; then stop fi else echo "===============================" echo "warn: $APP_MAINCLASS is not running" echo "===============================" fi}########################################
#(函数)检查程序运行状态#说明:#1、首先调用checkpid函数,刷新$psid全局变量#2、如果程序已经启动($psid不等于0),则提示正在运行并打印出pid,否则提示程序未运行########################################status() { checkpid if [ $psid -ne 0 ]; then echo "$APP_MAINCLASS is running!(pid=$psid)" else echo "$APP_MAINCLASS is not running!" fi}########################################
#(函数)打印系统环境参数########################################info() { echo "System Information:" echo "***************************************" echo `head -n 1 /etc/issue` echo `uname -a` echo echo "JAVA_HOME=$JAVA_HOME" echo `$JAVA_HOME/bin/java -version` echo echo "APP_HOME=$APP_HOME" echo "APP_MAINCLASS=$APP_MAINCLASS" echo "***************************************"}########################################
#读取脚本的第一个参数($1),进行判断#参数取值范围:{start|stop|restart|status|info}#如果参数不在指定范围之内,则打印帮助信息########################################case "$1" in 'start') start ;; 'stop') stop ;; 'restart') stop start ;; 'status') status ;; 'info') info ;; *) echo "Usage: $0 {start|stop|restart|status|info}" exit 1esacexit 0