eclipse匯出maven工程的可執行jar包
一、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目錄下所有的jar
CLASSPATH=$APP_HOME/classes
for 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=0
checkpid() {
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 1
esac
exit 0