【精】部署一个不依赖tomcat容器的应用

一个task项目,应用里边都是一些定时任务。我和新入职的高开商定程序部署不依赖于tomcat。

计划赶不上变化,任务开发完成还没等上线呢,哥们要离职了。工作交接时大概说了一下上线怎么部署。

结果呢,当我在linux测试服务器上部署时,可费了一些周折。之前都是把应用部署到tomcat下面的。那位高开说过,不依赖tomcat容器的部署方式已经不是新概念了。漫长的解决过程中,有同事建议我放弃,改用tomcat吧。我觉得有必要坚持下来,最终也坚持下来了。

一.先介绍一下项目

工程如下图。assembly/bin下有一个emax-paycenter-task.sh文件,主要是通过nohup命令来运行LauncherMain。高开说了,部署时将该shell文件放到应用的根目录下,通过执行它来启动程序。

image

emax-paycenter-task.sh文件里是如下命令,start用的是nohup命令:

image

LauncherMain.java里是一个main方法,用来初始化环境:

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.context.support.XmlWebApplicationContext;

import java.net.URL;
import java.util.concurrent.Semaphore;

/**
 * Description 启动方法
 * Date 2018/2/8 上午10:01
 */
public class LauncherMain {

    private static Logger logger= LoggerFactory.getLogger(LauncherMain.class);
    public static void main(String[] args) throws Exception {

        logger.info("init @Prop");
        Semaphore sp = new Semaphore(0);
        XmlWebApplicationContext xmlWeb = new XmlWebApplicationContext();
        xmlWeb.setConfigLocation("classpath*:*spring/spring-applicationContext.xml");
        String logbackCfg = "logback.xml";
        URL logURL = new ClassPathResource(logbackCfg).getURL();

        ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
        LoggerContext loggerContext = (LoggerContext) loggerFactory;

        JoranConfigurator configurator = new JoranConfigurator();
        configurator.setContext(loggerContext);
        configurator.doConfigure(logURL);

        xmlWeb.refresh();
        xmlWeb.start();
        sp.acquire();
    }

}

项目中涉及到的定时任务采用Spring的@Scheduled来实现:

@Component
public class AgentPayTask {

    @Autowired
    private LimitConfigDataHolder limitConfigDataHolder;

    @Autowired
    private AgentPayTaskService agentPayTaskService;

    private static Logger logger = LoggerFactory.getLogger(AgentPayTask.class);

    @Scheduled(cron ="0/5 * * * * ?")
    public void process() {
        System.out.println("AgentPayTask111");
        logger.info("AgentPayTask");
        Map<String, RateLimiterConfig> LimiterMap = limitConfigDataHolder.getAgentPayLimiter();
        agentPayTaskService.distributeTask(LimiterMap);
    }

}

二.linux部署

我在本地直接运行main方法,程序是没问题的,里面的定时任务都可以正常跑。

将maven打包后的emax-paycenter-task-1.0.0-SNAPSHOT-assembly.tar.gz解压部署到测试服务器上。最终执行命令

./emax-paycenter-task.sh start &

查看生成的nohup.out文件,发现总是找到class com.emax.paycenter.LauncherMain。

后来咨询运维,发现是没有给目录分配权限所致。

技能娴熟的运维又帮忙把emax-paycenter-task.sh里的命令修正了一下。最终如下:

image

再次按照上面命令启动程序,查看日志文件发现只有如下一条日志:

2018-03-21 15:11:45.381 [main] INFO  [com.emax.paycenter.LauncherMain] - init @Prop

多次测试发现,程序执行到sp.acquire();这条语句时,就不动了;我在这条语句后加打印日志结果也没打印出来;定时任务也没执行。

了解了一下Semaphore信号量,把permits改成0或1或其他值,都不行。

。。。。。一个小时。。。。

。。。。。两个小时。。。。

找同事帮助,无果。

。。。。。若干小时。。。。

灵感咋现!我将怀疑的焦点放到了spring context的设置这里,是不是压根都没有设置成功呢?

xmlWeb.setConfigLocation("classpath*:*spring/spring-applicationContext.xml");

莫非是各jar包里有同名的配置文件? 将路径参数"classpath:spring/spring-applicationContext.xml"改成"classpath:spring/spring-applicationContext.xml"后,查看nohup.out发现出现了新的问题:

[root@localhost emax-paycenter-task]# tail -f nohup.out 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:531)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:295)
    ... 11 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.emax.paycenter.api.service.IPayCenterFacade] 
found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. 
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:997)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:867)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:779)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:503)
    ... 13 more

同时,日志文件里存在类似问题:spring context初始化时出现了异常。项目中一个类“AgentPayTaskQueryServiceImpl”通过@Autowired依赖注入了另一个bean“IPayCenterFacade”。

而在spring context里找不到“IPayCenterFacade”这个依赖(NoSuchBeanDefinitionException),从而导致spring context创建AgentPayTaskQueryServiceImpl实例“agentPayTaskQueryServiceImpl”失败(BeanCreationException异常)。

image

最后,将spring applicationContext里对dubbo配置文件的import由

<import resource="classpath*:*spring/dubbo-applicationContext.xml"/>

改成

<import resource="classpath:spring/dubbo-applicationContext.xml"/>

就可以了。

image
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,084评论 19 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 47,144评论 6 342
  • 硬盘空间用尽是一件很让人头疼的事情,尤其是MacBook Air等设备上的固态硬盘可用的储存空间很少。下面为大家介...
    春寒夏末秋阅读 1,607评论 0 0
  • 古代诗歌荟萃缤纷,若星辰,而明暗有别,而那些最闪耀的诗人应该被历史所记住,今从唐代诗人中依个人愚见以及个人喜好...
    柚子的学长阅读 4,572评论 0 1
  • 这一天,停下了脚步,坐在十字路口, 吹着北京常有的风,看人来人往,车来车往 一群遛狗的人,对狗的爱胜于对人,...
    张小米_阅读 1,607评论 0 0

友情链接更多精彩内容