美文网首页
记一次Tomcat容器项目启动2次的问题解决

记一次Tomcat容器项目启动2次的问题解决

作者: lonmao | 来源:发表于2022-01-07 15:18 被阅读0次

    背景:
    自己玩的项目,基于若依框架进行二次业务开发,然后部署到服务器。
    服务器部署方案使用docker的Tomcat容器部署实例,请求打到docker的Nginx后根据规则转发到Tomcat上。

    表现:
    概率性第一次启动Tomcat容器后无法访问项目,访问提示根路径not found,重启容器后正常。
    观察启动日志,发现日志中吐出了2次项目的启动日志,同时伴随这一大堆的启动报错,但是项目可以正常访问,功能也正常。

    启动报错最突出的:

            Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [com.alibaba.druid.filter.stat.StatFilter@1dbef693] with key 'statFilter'; nested exception is javax.management.InstanceAlreadyExistsException: com.alibaba.druid.filter.stat:name=statFilter,type=StatFilter
     at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:628)
                    at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:550)
                    at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:432)
                    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:781)
                    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
                    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
                    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
                    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737)
                    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370)
                    at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
                    at org.springframework.boot.web.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:151)
                    at org.springframework.boot.web.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:131)
                    at org.springframework.boot.web.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:86)
                    at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:169)
                    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5139)
                    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                    ... 38 more
            Caused by: javax.management.InstanceAlreadyExistsException: com.alibaba.druid.filter.stat:name=statFilter,type=StatFilter
                    at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
                    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
                    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
                    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
                    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
                    at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
                    at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195)
                    at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:674)
                    at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:618)
                    ... 53 more
    

    问题原因:
    从上述描述已经报错InstanceAlreadyExistsException来看,初步怀疑是因为启动了2次项目,第二次启动的时候检测到InstanceAlreadyExists从而吐出的异常堆栈报错信息,那么理论上解决了2次启动的问题,启动日志也会干净了。

    关于启动2次项目,按理应该是Tomcat的问题,于是查资料与查看配置文件,然后发现server.xml中有如下配置:

    <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="false">
    <Context docBase="xxx" path="/" reloadable="true" />
    

    appBase="webapps"没记错的话是Tomcat的默认配置,其作用是启动Tomcat的时候部署webapps下的项目;
    而docBase="xxx"是我为了可以实现根路径访问项目配置的,xxx是war包的命名,其作用是访问根路径的时候,默认访问该项目(aaa.com/login),不然需要带上项目名才能访问到项目,例如 aaa.com/xxx/login;

    猜测问题出现在这里,appBase这边扫描部署了一次项目后,docBase再次部署,就会出现启动2次的问题了。

    问题解决:
    找到原因后对症下药即可。
    有2种方案,一种是直接干掉appBase(appBase=""),即不让Tomcat扫描自动部署webapps的所有项目,这样项目xxx只会被docBase扫描到,但是这里需要注意,要写成docBase="webapps/xxx",因为docBase是以appBase为基准的,即docBase实际上等于 appBase + docBase。
    还要注意的是,由于改了appBase,所以如果该Tomcat需要部署多个项目的话,均需要指定context去扫描(不过一般这种场景不多)。

    <Host name="localhost"  appBase="" unpackWARs="true" autoDeploy="false">
    <Context docBase="webapps/xxx" path="/" reloadable="true" />
    

    第二种方案就是你需要被docBase指定的项目就不要放在webapps下了,扫描不到你不就不会自动部署了么,你这个项目再自己单独指定路径去部署,例如放在和webapps同级目录bbb下,配置文件可以这么写:

    <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="false">
    <Context docBase="../bbb/xxx" path="/" reloadable="true" />
    

    使用相对路径即可。

    改为配置文件后重启实例,发现不再报错,也没有2次启动日志的输出了,同时内存占用约减少了150M,至此,问题解决。

    相关文章

      网友评论

          本文标题:记一次Tomcat容器项目启动2次的问题解决

          本文链接:https://www.haomeiwen.com/subject/napjcrtx.html