一、按照自定义的形式打包--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>