不要使用 maven-assembly-plugin
可能会报如下问题
Unable to locate Spring NamespaceHandler for XML schema namespace
这是由于所使用的 assembly 插件有 bug: 在将多个依赖打进同一个包时, 如果存在多个 spring 包的依赖, 则 META-INF/spring.handlers
和 META-INF/spring.schemas
的内容会被覆盖. 详情参见这里
解决办法: 换另一个插件 maven-shade-plugin
, 将打包插件替换为以下代码:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${artifactId}-${env}-${version}</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.yourMainClass</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.tooling</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
不要使用 java -jar
执行 jar 包时, 建议使用 java -cp
, 而不要使用 java -jar
方式, 两者的区别参见这里, 命令如下
java -cp xxx.jar com.example.yourMainClass args
建议指定 JVM 的内存大小
随着逻辑越来越复杂, 执行 Job 需要更多内存, 这时可能报内存溢出错误 java.lang.OutOfMemoryError: Java heap space
, 这时可以在 java
命令之后增加如下参数, 增大执行时的内存.
-Xms2048M -Xmx2048M
建议用 Spring 管理任务
随着项目越来越复杂, 可能会有很多任务, 建议用一个 Job, 多个 Task 的方式组织代码. 一个 Job 是代码入口, 内容如下
public class Job {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("输入参数不够!");
System.exit(0);
}
String cmd = args[0];
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:config/spring/local/appcontext-*.xml");
AbstractTask task = (AbstractTask) context.getBean(cmd);
task.setArgs(args);
task.start();
System.exit(0);
}
}
然后写一个 Task
接口, 代码如下
public interface Task {
String getTaskName();
void run();
void start();
}
接着写个抽象类 AbstractTask
, 代码如下
@Slf4j
@Data
public abstract class AbstractTask implements Task {
private String[] args;
@Override
public String getTaskName() {
return getClass().getSimpleName();
}
@Override
public void start() {
log.info("Begin to run {} at {}", getTaskName(), new Date());
run();
log.info("Complete {} at {}", getTaskName(), new Date());
}
}
接下来实现一个任务时, 只需要继承抽象类 AbstractTask
, 然后实现 run()
方法即可. 在实现过程中, 可以通过 getArgs()
方法, 获取外部传入的参数. 执行任务统一调用 start()
方法.
这样子组织代码, 再多的任务的不用担心啦!