96SEO 2026-02-19 20:14 14
前两天由于项目需要一个windows上的批处理任务kitchen.bat需要接到mq的消息通知后执行为了快速实现这里我们通过springboot写了一个jar程序用于接收mq的消息并调用bat文件。

调用windows的批处理脚本bat并支持传参可根据配置设置并发同时消费多个mq消息调用多个批处理脚本确保java程序能一直正常运行如果有假死或者宕机了可以自动重启批处理脚本执行失败了则再将信息重新放回到mq的队列尾部等待下次执行
用于调用windows服务器命令通过环境变量配置程序运行的参数如mq信息、和执行的批处理脚本命令路径、并发等通过rabbitmq的手工ack来确定消息是否处理成功及并发实现通过actuator来判断java程序是否健康通过windows定时任务来定时检查java程序是否正常提供服务如果不正常则触发重启jar应用通过mavenant打包程序将可执行程序jar及相关脚本打包成一个zip文件方便发给使用方使用
cn.iccboy.kitchen.common;import
lombok.extern.slf4j.Slf4j;import
标志1--InputStream2--ErrorStream*/private
InputStreamReader(inputStream);BufferedReader
BufferedReader(inputStreamReader))
e.getMessage());}}).start();}public
StrUtil.splicingWithSpace(command,
Runtime.getRuntime().exec(cmd);processStreamHandler(process.getInputStream(),
1);processStreamHandler(process.getErrorStream(),
{log.error(【异常】process.waitFor:{}
e.getMessage());}log.info(执行命令{},
}上面的程序中一定要注意的是process.getErrorStream()
一定要将命令行执行输出的信息输出流和错误信息错误流都从缓冲区读取出来不然会导致程序执行阻塞。
在runtime执行大点的命令中输入流和错误流会不断有流进入存储在JVM的缓冲区中如果缓冲区的流不被读取被填满时就会造成runtime的阻塞。
所以在进行比如大文件复制等的操作时需要不断的去读取JVM中的缓冲区的流防止Runtime的死锁阻塞。
这里通过actuator来实现首先程序集成actuator,由于是springboot项目所以很方便。
然后通过一个简单的java程序CheckActuator来访问actuator的http地址通过返回值来判断jar程序是否运行正常然后通过windows的脚本checkHealth.bat来调用CheckActuator根据返回值在进行java程序的重启等操作。
pom.xml增加actuator及prome***us的配置
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencydependencygroupIdio.micrometer/groupIdartifactIdmicrometer-registry-prome***us/artifactId/dependency上的版本会根据springboot对应版本自动集成
management:health:rabbit:enabled:
trueendpoints:web:exposure:include:
[prome***us,health]endpoint:health:show-details:
alwaysmetrics:export:prome***us:enabled:
当然也可以通过windows的批处理命令直接访问actuator的地址来判断服务是否正常。
该类用于检查程序是否健康通过actuator进行判断是否健康**
http://127.0.0.1:8000/actuator/health;if(args
args[0];}testUrlWithTimeOut(url);}public
url.openConnection();conn.setConnectTimeout(timeOutMillSeconds);conn.connect();InputStream
conn.getInputStream();BufferedReader
sb.toString().contains(HEALTH_FLAG);if(healthFlag)
e.getMessage());System.exit(1);}}
}我将上面的CheckActuator.java文件放到maven项目的test/java/跟目录下后面会通过ant命令将.class移动到指定位置
上面的springboot项目会通过http服务其运行的端口是8000下面脚本会通过8000端口来获取对应的进程pid
yMd%date:~0,4%-%date:~5,2%-%date:~8,2%
strFile%strPath%log/checkHealth-%date:~0,4%%date:~5,2%%date:~8,2%.log
%strPath%%filename%windows定时任务配置
checkBat%strPath%checkHealth.bat
pause上面的xxx-health-check是定时任务的名字
表示每2分钟执行一次命令。
上面是通过命令配置的定时任务也可以通过windows的图形管理界面【计划任务】配置。
${K_PORT:8000}servlet:context-path:
${K_MQ_HOST:172.18.1.100}password:
${K_MQ_USERNAME:mq}connection-timeout:
15000listener:simple:acknowledge-mode:
每个消费每次预去取几个消息jackson:date-format:
${K_BAT_PATHS:C:\invoke.bat}可通过设置系统的环境变量来改变配置可设置的变量包含
变量说明默认值K_PORT程序运行的http服务端口8000K_MQ_HOSTrabbitmq
服务ip172.18.1.100K_MQ_PORTrabbitmq
密码123456K_BAT_PATHSbat脚本路径可以配置多个通过英文逗号分隔配置多个就会启动多个消费者,如C:\invoke_1.bat,C:\invoke_2.batC:\invoke.batK_WORKS每个消费者的并发数。
如K_BAT_PATHS配置了3个命令K_WORKS
cn.iccboy.kitchen.common.CmdUtil;
cn.iccboy.kitchen.common.ThreadUtil;
com.rabbitmq.client.MessageProperties;
org.springframework.amqp.rabbit.annotation.RabbitListener;
org.springframework.amqp.support.AmqpHeaders;
org.springframework.messaging.Message;
org.springframework.messaging.handler.annotation.Headers;import
java.nio.charset.StandardCharsets;
cn.iccboy.kitchen.mq.TopicRabbitMqConfig.EXCHANGE_DATA;
cn.iccboy.kitchen.mq.TopicRabbitMqConfig.KEY_INDEX_PROCESS;/***
TopicRabbitMqConfig.QUEUE_INDEX_PROCESS)public
headers.get(AmqpHeaders.DELIVERY_TAG);try
{log.info([start]第{}执行器,消息内容:{},
message.getPayload());if(status
{log.info([err_1]第{}执行器,消息内容:{}加工脚本执行异常状态码{},seq,
RuntimeException(脚本执行异常);}log.info([end]第{}执行器执行完成:{},
{ThreadUtil.sleep(1000);log.error([err]第{}执行器,执行异常重新进入队列:{},
e);//channel.basicNack(deliveryTag,
将处理错误的消息放到重新队列尾部channel.basicPublish(EXCHANGE_DATA,KEY_INDEX_PROCESS,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getPayload().getBytes(StandardCharsets.UTF_8));}
确认已处理channel.basicAck(deliveryTag,false);}}}
org.springframework.beans.MutablePropertyValues;
org.springframework.beans.factory.support.BeanDefinitionRegistry;
org.springframework.beans.factory.support.RootBeanDefinition;
org.springframework.context.EnvironmentAware;
org.springframework.context.annotation.Configuration;
org.springframework.context.annotation.Import;
org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
org.springframework.core.env.Environment;
org.springframework.core.type.AnnotationMetadata;import
Import(DynamicBuildMqReceiveBean.ImportConfig.class)
environment.getProperty(shell.paths,
registerBeanDefinitions(AnnotationMetadata
RootBeanDefinition();beanDefinition.setBeanClass(CmdMqReceive.class);MutablePropertyValues
MutablePropertyValues();values.addPropertyValue(batPath,
batPath);values.addPropertyValue(seq,
seq);beanDefinition.setPropertyValues(values);registry.registerBeanDefinition(CmdMqReceive.class.getName()
}上面通过ImportBeanDefinitionRegistrar的方式
buildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/pluginplugingroupIdorg.apache.maven.plugins/groupIdartifactIdmaven-antrun-plugin/artifactIdversion1.8/versionexecutionsexecutionidclean/idphaseclean/phaseconfigurationtargetdelete
file${basedir}/shell/CheckActuator.class//target/configurationgoalsgoalrun/goal/goals/executionexecutionidtest-compile/idphasetest-compile/phaseconfigurationtargetcopy
file${project.build.directory}/test-classes/CheckActuator.classtodir${basedir}/shell
//target/configurationgoalsgoalrun/goal/goals/executionexecutionidpackage/idphasepackage/phaseconfigurationtargetdelete
dir${project.build.directory}/kitchen-mq-bin/mkdir
dir${project.build.directory}/kitchen-mq-bin/copy
todir${project.build.directory}/kitchen-mq-bin
file${project.build.directory}/${project.name}-${project.version}.jar
todir${project.build.directory}/kitchen-mq-bin
destfile${basedir}/kitchen-mq-bin.zipfileset
dir${project.build.directory}/kitchen-mq-bininclude
name*//fileset/zip/target/configurationgoalsgoalrun/goal/goals/execution/executions/plugin/plugins/build项目结构如下图
package上面命令执行完成后在项目的跟目录会产生一个压缩包kitchen-mq-bin.zip,将压缩包直接拷贝到目标服务器解压即可。
解压后直接执行新增-健康检查定时任务.bat即可。
2分钟后就会启动程序。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback