【Linux】shell调用Java程序main方法通过crontab定时执行
2016-06-28 13:09
1126 查看
最近一个项目需要写一个batch定时读取文件往数据库里插入记录,第一次写,遇到好多问题,记录一下。
先从shell如何调用java说起
建立如下目录结构
batch 根目录
├── bin shell放置目录(如果直接放java class也放这里)
│ ├── 1.sh
│ ├── test.sh
│ └── startup.sh
├── libs 引用jar包放置目录
│ ├── commons-io-2.4.jar
│ ├── commons-lang3-3.3.2.jar
│ ├── ini4j-0.5.4.jar
│ ├── junit-3.8.1.jar
│ ├── log4j-1.2.17.jar
│ ├── postgresql-9.3-1102-jdbc41.jar
│ └── myjar.jar 自己的jar
├── lock 锁文件(空文件)
└── logs 程序log目录
├── cron.log
└── myjar.log
然后是shell脚本
startup.sh
第1行声明shell类型
2-4行输出一些时间信息
6-8行分别定义了一些变量后面会用到
10行让程序进入到自己shell脚本的bin目录,如果使用cron执行这很重要,因为libs文件夹定义的是相对路径,而cron的默认执行路径则找不到,如果手工进入到bin目录下执行则无所谓
11-24行只做了一件事情,就是将bin目录,batch目录,libs目录下的所有jar包,全部加入到classpath中,生成一长串字符串如下:
只不过是用了一个append()方法和一个for循环实现了字符串的拼接,如果jar包不多的话手工写上去也是完全可以的。
26行打印了一下生成的$CLASSPATH变量的值
29行是真正的调用java执行main()方法,要说的是 在前面如果加上“nohup ”的话,java的执行log就会直接输出到当前目录下的nohup.log文件里。如果是手工执行在最后加上“ $”的话程序将会后台执行,也就是说关闭命令行窗口并不会中断程序的执行,不过这种方法中shell的进程并不会等待java方法执行完成,而是立即完成。
-classpath 后面的$CLASSPATH是告诉java去什么地方找到用到的jar包,我的程序是导出的jar包,我也同样把我的jar包放入到了这个目录就可以了,如果是编译的class文件的话放到bin目录下也可以。
32行输出log
33行程序正常退出
如果是手工通过shell调用java那以上文字就已经搞定了
下面说如何通过crontab调用shell
在命令行下输入
可以打开cron任务的编辑界面
注意的是cron是区分用户的,每个用户的cron是单独的
这样写的话就是每分钟执行一次指定的shell了
前面的几个* 分别是minute(分),hour(小时),day
of month(日期),month(月份), day of week(星期),具体的可以查询一下
这个只是每分钟执行一次,下面的命令可以将执行的log输入到指定文件也就是shell中的echo
但是有好多时候,比如我的需求,如果数据量过大,上一个batch还没执行完则不希望下一个batch也执行,本次不执行就可以了这个需求可以通过flock来实现
上面的命令前面就是用flock命令去给一个文件上锁,这个锁是一个全局锁如果其它命令也来获取这个文件的锁的而获取不到的话则不会被执行,这个锁文件是什么文件无所谓。
后面的参数是获取一个独占锁,如果获取不到,则等待10秒钟
-s,--shared: 获得一个共享锁
-x,--exclusive:获得一个独占锁
-u,--unlock: 移除一个锁,通常是不需要的,脚本执行完会自动丢弃锁
-n,--nonblock: 如果没有立即获得锁,直接失败而不是等待
-w,--timeout: 如果没有立即获得锁,等待指定时间
-o,--close: 在运行命令前关闭文件的描述符号。用于如果命令产生子进程时会不受锁的管控
-c,--command: 在shell中运行一个单独的命令
-h,--help 显示帮助
-V,--version: 显示版本
一些参数贴出来
这样,通过crontab,调用shell,实现java main()方法的定期执行,并且防止同一时间重复执行就完成了。
这样做的好处是不用通过java来判断多重执行,java判断起来也不是很方便。
有一些小补充。
1,shell里面进入目录的那句话很重要,因为这个找了好久的原因。
2,执行shell的时候可以用sh -x startup.sh来执行输出详细执行log。
3,cron的执行log在/var/log/cron文件里面,可以查看执行详细。
4,我的java程序log是自己用log4j出力到logs下面的。
先从shell如何调用java说起
建立如下目录结构
batch 根目录
├── bin shell放置目录(如果直接放java class也放这里)
│ ├── 1.sh
│ ├── test.sh
│ └── startup.sh
├── libs 引用jar包放置目录
│ ├── commons-io-2.4.jar
│ ├── commons-lang3-3.3.2.jar
│ ├── ini4j-0.5.4.jar
│ ├── junit-3.8.1.jar
│ ├── log4j-1.2.17.jar
│ ├── postgresql-9.3-1102-jdbc41.jar
│ └── myjar.jar 自己的jar
├── lock 锁文件(空文件)
└── logs 程序log目录
├── cron.log
└── myjar.log
然后是shell脚本
startup.sh
#!/bin/sh echo "" echo "----------------------------------" echo "start at `date '+%Y-%m-%d %H:%M:%S'` ..." JAVA_HOME=/usr/java/jdk1.8.0_45 MAIN_CLASS=com.superbatch.batch.DetectLogBatch SH_DIR=/usr/local/ee4one_batch/bin cd $SH_DIR dir="." temp="" libs="../libs/*" append(){ temp=$temp":"$1 } for file in $libs do append $file done export CLASSPATH=$dir:../$temp echo $CLASSPATH #nohup ${JAVA_HOME}/bin/java -classpath ${CLASSPATH} ${MAIN_CLASS} echo "finished at `date '+%Y-%m-%d %H:%M:%S'` ..." exit 0
第1行声明shell类型
2-4行输出一些时间信息
6-8行分别定义了一些变量后面会用到
10行让程序进入到自己shell脚本的bin目录,如果使用cron执行这很重要,因为libs文件夹定义的是相对路径,而cron的默认执行路径则找不到,如果手工进入到bin目录下执行则无所谓
11-24行只做了一件事情,就是将bin目录,batch目录,libs目录下的所有jar包,全部加入到classpath中,生成一长串字符串如下:
.:../:../libs/commons-io-2.4.jar:../libs/commons-lang3-3.3.2.jar:../libs/ini4j-0.5.4.jar:../libs/junit-3.8.1.jar:../libs/log4j-1.2.17.jar:../libs/postgresql-9.3-1102-jdbc41.jar:../libs/myjar.jar
只不过是用了一个append()方法和一个for循环实现了字符串的拼接,如果jar包不多的话手工写上去也是完全可以的。
26行打印了一下生成的$CLASSPATH变量的值
29行是真正的调用java执行main()方法,要说的是 在前面如果加上“nohup ”的话,java的执行log就会直接输出到当前目录下的nohup.log文件里。如果是手工执行在最后加上“ $”的话程序将会后台执行,也就是说关闭命令行窗口并不会中断程序的执行,不过这种方法中shell的进程并不会等待java方法执行完成,而是立即完成。
-classpath 后面的$CLASSPATH是告诉java去什么地方找到用到的jar包,我的程序是导出的jar包,我也同样把我的jar包放入到了这个目录就可以了,如果是编译的class文件的话放到bin目录下也可以。
32行输出log
33行程序正常退出
如果是手工通过shell调用java那以上文字就已经搞定了
下面说如何通过crontab调用shell
在命令行下输入
crontab -e
可以打开cron任务的编辑界面
注意的是cron是区分用户的,每个用户的cron是单独的
*/1 * * * * /usr/local/batch/bin/startup.sh
这样写的话就是每分钟执行一次指定的shell了
前面的几个* 分别是minute(分),hour(小时),day
of month(日期),month(月份), day of week(星期),具体的可以查询一下
这个只是每分钟执行一次,下面的命令可以将执行的log输入到指定文件也就是shell中的echo
*/1 * * * * /usr/local/batch/bin/startup.sh >>/usr/local/batch/logs/cron.log
但是有好多时候,比如我的需求,如果数据量过大,上一个batch还没执行完则不希望下一个batch也执行,本次不执行就可以了这个需求可以通过flock来实现
*/1 * * * * flock -xw 10 /usr/local/ee4one_batch/lock -c "sh /usr/local/ee4one_batch/bin/test.sh >> /usr/local/ee4one_batch/logs/cron.l
上面的命令前面就是用flock命令去给一个文件上锁,这个锁是一个全局锁如果其它命令也来获取这个文件的锁的而获取不到的话则不会被执行,这个锁文件是什么文件无所谓。
后面的参数是获取一个独占锁,如果获取不到,则等待10秒钟
-s,--shared: 获得一个共享锁
-x,--exclusive:获得一个独占锁
-u,--unlock: 移除一个锁,通常是不需要的,脚本执行完会自动丢弃锁
-n,--nonblock: 如果没有立即获得锁,直接失败而不是等待
-w,--timeout: 如果没有立即获得锁,等待指定时间
-o,--close: 在运行命令前关闭文件的描述符号。用于如果命令产生子进程时会不受锁的管控
-c,--command: 在shell中运行一个单独的命令
-h,--help 显示帮助
-V,--version: 显示版本
一些参数贴出来
这样,通过crontab,调用shell,实现java main()方法的定期执行,并且防止同一时间重复执行就完成了。
这样做的好处是不用通过java来判断多重执行,java判断起来也不是很方便。
有一些小补充。
1,shell里面进入目录的那句话很重要,因为这个找了好久的原因。
2,执行shell的时候可以用sh -x startup.sh来执行输出详细执行log。
3,cron的执行log在/var/log/cron文件里面,可以查看执行详细。
4,我的java程序log是自己用log4j出力到logs下面的。
相关文章推荐
- win10安装bash
- Shell while循环
- Shell for循环
- Shell case esac语句
- Shell if else语句
- shell printf命令:格式化输出语句
- 使用 PowerShell 自动登录 Azure
- 使用 PowerShell 自动登录 Azure
- 10.Shell操作符
- 使用 PowerShell 自动登录Azure
- ubuntu系统shell 中source: not found错误
- 使用PowerShell .Net获取电脑中的UUID
- shell编程初探
- Managing linux Shell Jobs
- Bash shell 的算术运算有四种方式
- HBase shell 中的十六进制数值表示
- 使用PowerShell .Net获取电脑中的UUID
- shell编程代码备忘
- 用了就会上瘾的几个shell命令行快捷键
- linux----->shell高级编程----grep应用