一、按照自定义的形式打包--assembly
1、maven-jar-plugin插件
指定main入口,打包的时候可以配置排哪些配置文件不打到jar包里
2、maven-dependency-plugin插件
1.需要某个特殊的 jar包,但是有不能直接通过maven依赖获取,或者说在其他环境的maven仓库内不存在,那么如何将我们所需要的jar包打入我们的生产jar包中。
2.某个jar包内部包含的文件是我们所需要的,或者是我们希望将它提取出来放入指定的位置 ,那么除了复制粘贴,如何通过maven插件实现呢
3、maven-assembly-plugin插件
assembly打包插件 按照自己的方式打包
<build>
<!--1、执行配置文件的类路径-->
<resources>
<resource>
<directory>src/main/resources/common</directory>
</resource>
<resource>
<directory>src/main/resources/${profiles.active}</directory>
</resource>
</resources>
<plugins>
<!-- 2、指定main入口打包的时候排除配置文件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.emax.paycenter.App</mainClass>
</manifest>
</archive>
<excludes><!--不把配置文件打的jar包里面-->
<exclude>*.properties</exclude>
<exclude>*.xml</exclude>
<exclude>spring/*.*</exclude>
<exclude>mq/*.*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<!-- 生成emax-paycenter-payorderquery-polling-0.0.1-SNAPSHOT-bak.jar 没有此配置会报以下错
Failed to execute goal org.apache.maven.plugins:maven-jar-plugin:3.0.2:jar (make-assembly) on project com.emax-paycenter-payorderquery-polling:
You have to use a classifier to attach supplemental artifacts to the project instead of replacing them
-->
<classifier>bak</classifier>
</configuration>
</execution>
</executions>
</plugin>
<!--3、依赖的jar包存放位置
①需要某个特殊的 jar包,但是有不能直接通过maven依赖获取,或者说在其他环境的maven仓库内不存在,那么如何将我们所需要的jar包打入我们的生产jar包中。
②某个jar包内部包含的文件是我们所需要的,或者是我们希望将它提取出来放入指定的位置 ,那么除了复制粘贴,如何通过maven插件实现呢
-->
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<!--将所有的依赖jar包打到target的lib目录下-->
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<type>jar</type>
<includeTypes>jar</includeTypes>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
<!--将emax-paycenter-task-manager.jar包里的配置文件拷贝出来放在target/emax-paycenter-task-manager目录里
然后再用assembly.xml打到jar包外面-->
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>emax</groupId>
<artifactId>emax-paycenter-task-manager</artifactId>
<version>1.0.0-SNAPSHOT</version>
<includes>datasource/**</includes>
<outputDirectory>${project.build.directory}/emax-paycenter-task-manager</outputDirectory>
</artifactItem>
<artifactItem>
<groupId>emax</groupId>
<artifactId>emax-paycenter-task-manager</artifactId>
<version>1.0.0-SNAPSHOT</version>
<includes>spring/**</includes>
<outputDirectory>${project.build.directory}/emax-paycenter-task-manager
</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<!--4、assembly打包插件 按照自己的方式打包-->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptor>emax-paycenter-payorderquery-polling/src/main/assembly/assembly.xml</descriptor>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!--指定各环境 dong-->
<profiles>
<profile>
<!-- 开发环境 -->
<id>develop</id>
<properties>
<profiles.active>develop</profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<!-- 测试环境 -->
<id>test</id>
<properties>
<profiles.active>test</profiles.active>
</properties>
</profile>
<profile>
<!-- 准生产环境 -->
<id>forecast</id>
<properties>
<profiles.active>forecast</profiles.active>
</properties>
</profile>
<profile>
<!-- 生产环境 -->
<id>production</id>
<properties>
<profiles.active>production</profiles.active>
</properties>
</profile>
</profiles>
4、assembly.xml文件
<!--
- Copyright 1999-2011 Alibaba Group.
-
- 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.
-->
<assembly>
<id>assembly</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}/emax-paycenter-task-manager</directory>
<outputDirectory>emax-paycenter-task-manager-resource</outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<directory>src/main/assembly/bin</directory>
<outputDirectory></outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<directory>src/main/resources/${profiles.active}</directory>
<outputDirectory></outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<directory>src/main/resources/common</directory>
<outputDirectory></outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>lib</outputDirectory>
</dependencySet>
</dependencySets>
</assembly>
5、main方法启动
public class App {
private static Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
logger.info("init @Prop");
Semaphore sp = new Semaphore(0);
XmlWebApplicationContext xmlWeb = new XmlWebApplicationContext();
xmlWeb.setConfigLocation("classpath:spring/spring-applicationContext.xml");
xmlWeb.refresh();
//注册java的关闭钩子 配合kill -19优雅的关闭spring程序
xmlWeb.registerShutdownHook();
xmlWeb.start();
logger.info("程序启动完成");
try {
sp.acquire();
} catch (Exception e) {
logger.error("Semaphore.acquire()异常:", e);
} catch (Throwable e) {
logger.error(e.getMessage());
} finally {
logger.info("finally");
sp.release();
}
logger.info("init @Prop over");
}
}
6、main程序启动脚本
emax-paycenter-payorderquery-polling.sh
#!/bin/bash
export BASE_DIR=$(dirname $0)/
export PATH=/usr/java/jdk1.7.0_79/bin:$PATH
export JAR_DIR=/var/travel/emax-paycenter-payorderquery-polling
export PID_DIR=/var/travel/emax-paycenter-payorderquery-polling
export JAVA_OPS="-DLC_CTYPE=UTF-8 -Dfile.encoding=UTF-8 -Xms512m -Xmx1024m -XX:+TieredCompilation -Djava.net.preferIPv4Stack=true -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:+DisableExplicitGC"
if [ "$1" = "start" ] ; then
nohup java ${JAVA_OPS} -Djava.security.egd=file:/dev/./urandom -cp ${JAR_DIR}:lib/* com.emax.paycenter.App >/dev/null 2>&1 &
elif [ "$1" = "stop" ] ; then
sh shutdown-tomcat.sh emax-paycenter-payorderquery-polling
elif [ "$1" = "restart" ] ; then
sh shutdown-tomcat.sh emax-paycenter-payorderquery-polling
nohup java ${JAVA_OPS} -Djava.security.egd=file:/dev/./urandom -cp ${JAR_DIR}:lib/* com.emax.paycenter.App >/dev/null 2>&1 &
fi
shutdown-tomcat.sh
echo "杀进程开始"
ID=`ps -ef | grep java | grep $1|awk '{print $2}'`
echo $ID
for id in $ID
do
kill -15 $id
echo "killed$id"
done
echo "杀进程结束"
真正要执行的start/stop/restart 命令
echo "启动应用"
/var/travel/emax-paycenter-payorderquery-polling/
./emax-paycenter-payorderquery-polling.sh start
echo "停止应用"
/var/travel/emax-paycenter-payorderquery-polling/
./emax-paycenter-payorderquery-polling.sh stop
echo "重启应用"
/var/travel/emax-paycenter-payorderquery-polling/
./emax-paycenter-payorderquery-polling.sh restart
注意:如果关闭java进程的话,用kill -9会强杀进程,若果spring的bean做了一些对象销毁钱的处理操作,kill -9时将不能实现,因为spring程序是非正常关闭的,如何优雅地关闭一个java程序呢?
优雅关闭程序的方法:注册一个关闭钩子,执行kill -15命令关闭程序
1 在主线程中注册关闭钩子。
在关闭钩子中,设置标示不能处理新的业务(如关闭mq的消费者,关闭tcp连接的监听端口等)。
循环等待业务流程的处理完毕。(或者在关闭钩子中睡眠一段时间)
2 关闭时,发送kill -15 信号(不能是kill -9 信号,否则关闭钩子不起作用)
注册关闭钩子
public class App {
private static Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
logger.info("== init context");
try{
final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/spring-applicationContext.xml"});
// 杀java程序执行kill -15 时 会回调此函数 xmlWeb.registerShutdownHook();即实现的此原理去停止spring程序
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
logger.info("关程序前处理");
//TODO... ...关闭mq消费者等... ...
//正常关闭spring程序
context.close();
logger.info("处理完成");
}
});
context.start();
logger.info("== context start");
}catch(Exception e){
logger.error("== application start error:", e);
return;
}
synchronized (App.class) {
while (true) {
try {
App.class.wait();
} catch (InterruptedException e) {
logger.error("== synchronized error:", e);
}
}
}
}
}
registerShutdownHook();即实现的此原理去停止spring程序,上面的程序可简写为
public class App {
private static Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
logger.info("== init context");
try{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/spring-applicationContext.xml"});
context.registerShutdownHook();
context.start();
logger.info("== context start");
}catch(Exception e){
logger.error("== application start error:", e);
return;
}
synchronized (App.class) {
while (true) {
try {
App.class.wait();
} catch (InterruptedException e) {
logger.error("== synchronized error:", e);
}
}
}
}
}
SIGNKILL(9) 和 SIGNTERM(15) 的区别在于:
SIGNKILL(9) 的效果是立即杀死进程. 该信号不能被阻塞, 处理和忽略。
SIGNTERM(15) 的效果是正常退出进程,退出前可以被阻塞或回调处理。并且它是Linux缺省的程序中断信号。
由此可见,SIGNTERM(15) 才是理论上标准的kill进程信号。
如果java程序是dubbo程序,也可以使用dubbo提供的main方法:com.alibaba.dubbo.container.main 来启动关闭程序详情看dubbo的介绍
二、普通的打包形式和Dubbo打包形式
<!-- 1、指定类路径 -->
<build>
<finalName>bigpay-app-order-polling</finalName>
<resources>
<resource>
<targetPath>${project.build.directory}/classes</targetPath>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<!-- 结合com.alibaba.dubbo.container.Main
将类路径下(resource)的总的配置文件 spring-context.xml 拷贝到 ${project.build.directory}/classes/META-INF/sping 路径下
因为com.alibaba.dubbo.container.Main就是默认取此路径下去读取spring的配置文件的
如果是普通的打包形式可以不要这一段
-->
<resource>
<targetPath>${project.build.directory}/classes/META-INF/spring</targetPath>
<directory>src/main/resources/spring</directory>
<filtering>true</filtering>
<includes>
<include>spring-context.xml</include>
</includes>
</resource>
</resources>
<!-- 2、打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!--将target/classes/ 路径下的东西打到jar包里去-->
<classesDirectory>target/classes/</classesDirectory>
<archive>
<manifest>
<mainClass>com.bigpay.app.polling.App</mainClass>
<!--<mainClass>com.alibaba.dubbo.container.Main</mainClass>-->
<!-- 打包时 MANIFEST.MF文件不记录的时间戳版本 -->
<useUniqueVersions>false</useUniqueVersions>
<addClasspath>true</addClasspath>
<!--依赖的jar包的路径-->
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<!-- 3、依赖的jar包存放的位置 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<type>jar</type>
<includeTypes>jar</includeTypes>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>