是时候闭环Java应用了

开发 开发工具
今天的文章只关注闭环Java应用带来的好处。首先介绍下应该如何部署应用,然后介绍下什么是闭环Java应用,它的好处和如何搭建。

[[177168]]

你曾经因为部署/上线而痛苦吗?你曾经因为要去运维那改配置而烦恼吗?在我接触过的一些部署/上线方式中,曾碰到过以下一些问题:

1、程序代码和依赖都是人工上传到服务器,不是通过工具进行部署和发布;

2、目录结构没有规范,jar启动时通过-classpath任意指定;

3、fat jar,把程序代码、配置文件和依赖jar都打包到一个jar中,改配置文件太费劲;

4、不管是非web应用还是web应用都部署到web容器环境,如Tomcat;

5、web应用还需要先在服务器上安装好环境(如装Tomcat)才能部署,想升级版本或者换个容器太难了;

6、线上参数修改还需要找运维,痛苦。

还有如没有自动部署平台,回滚到上一个版本那可真是天方夜谈;增量包而非全量包,无法自由在在的回滚;前端代码直接覆盖而非版本化,难快速回滚,出问题要清理CDN,痛苦;ngx_lua项目时不按照项目的方式部署,在服务器上随意修改代码,导致某些服务器忘记修改或者版本不一致,排查问题太痛苦。

还有很多部署中不好的方式,但是本文只关注闭环Java应用带来的好处。首先介绍下应该如何部署应用,然后介绍下什么是闭环Java应用,它的好处和如何搭建。

应该如何部署应用

应该如何部署应用

项目

项目中应该包括了所有要执行的代码、启停脚本,比如非web应用

部署应用项目

web应用

部署应用项目web应用

打包应用后,会按照相应的目录结构构建。如果项目使用maven,可以使用maven-assembly-plugin进行按照相应的目录结构构件。

即项目、打包的应用要按照统一的风格来实施。

自动部署系统

自动部署系统负责打包应用(比如执行mvn相应的命令即可)、抽包(从指定目录抽取要部署的代码,如target/nonweb-example-package目录)、部署代码(发布代码,将代码同步到宿主机器)、启停应用(配置指定的启停脚本并调用)。

自动部署除了这些功能外,应该还有如发布历史管理(回滚)、分组管理(如不同机房不同的配置文件)、配置管理(如要修改启动/停止脚本、修改配置文件[不同机房不同的配置]、参数管理[如jvm参数等])等。

宿主机器

即代码部署到的机器,它应该只安装最小化环境,如只需要装JDK即可,像Tomcat是不需要安装的,由应用决定使用哪个容器。

通过增加自动部署系统可以更好的进行项目的统一发布、管理和回滚。

闭环Java应用

闭环Java应用指Java代码、容器、配置文件、启停脚本等都在同一处维护,修改配置文件、修改环境参数、更改容器类型等都不需要到宿主机器上进行更改。宿主机器只提供基本运行环境,如仅部署JDK环境即可,不需要部署如Tomcat容器,需要什么容器,都是在Java应用中指定。

这样的好处是配置文件修改、JVM参数修改、容器的选择都可以在Java应用中配置,形成闭环。

闭环Java应用的目的主要是让Java应用能自启动,这样程序的控制权就在我们手里,而不是运维手里。而我们更懂我们的程序。

随着微服务概念的流行,spring boot也受到大家的热捧。spring boot能帮助我们快速构建基于spring的应用;其能方便创建自启动应用、可以嵌入各种容器(如Tomcat、Jetty)、提供了一些starter pom用于简化配置文件、自动化配置(只需要引入相关的pom,就自动获得了某些功能)等。

在介绍spring boot之前,我们看下在以前是怎么构建闭环Java应用。

从零构建非web应用

项目结构

从零构建非web应用 项目结构

本示例演示了构建一个非web应用RPC服务生产者(如Dubbo服务),还可以构建如Worker类型的应用,他们本身不需要web容器,作为普通的java应用启动即可。

maven依赖(pom.xml)

需要自己添加如spring-core、spring-context等相关依赖,此处就不展示了。

打包配置(pom.xml)

nonweb-example\pom.xml

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-assembly-plugin</artifactId> 
    <version>2.6</version> 
    <configuration> 
        <descriptor>src/assembly/assembly.xml</descriptor> 
        <finalName>${project.build.finalName}</finalName> 
    </configuration> 
    <executions> 
        <execution> 
            <phase>package</phase> 
            <goals> 
                <goal>directory</goal> 
            </goals> 
        </execution> 
    </executions> 
</plugin> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

使用maven-assembly-plugin进行打包;打包配置如下:

<id>package</id> 
<formats> 
    <format>dir</format> 
</formats> 
<includeBaseDirectory>false</includeBaseDirectory> 
<fileSets> 
    <!-- 可执行文件 --> 
    <fileSet> 
        <directory>src/bin</directory> 
        <outputDirectory>bin</outputDirectory> 
        <includes> 
            <include>*.bat</include> 
        </includes> 
        <lineEnding>dos</lineEnding> 
    </fileSet> 
    <fileSet> 
        <directory>src/bin</directory> 
        <outputDirectory>bin</outputDirectory> 
        <includes> 
            <include>*.sh</include> 
        </includes> 
        <lineEnding>unix</lineEnding> 
        <fileMode>0755</fileMode> 
    </fileSet> 
    <!-- classes --> 
    <fileSet> 
        <directory>${project.build.directory}/classes</directory> 
        <outputDirectory>classes</outputDirectory> 
    </fileSet> 
</fileSets> 
<!-- 依赖jar包 --> 
<dependencySets> 
    <dependencySet> 
        <outputDirectory>lib</outputDirectory> 
        <excludes> 
            <exclude>com.jd:nonweb-example</exclude> 
        </excludes> 
    </dependencySet> 
</dependencySets> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

主要有三组配置:

  • formats:打包格式,此处使用的是dir,还可以是zip、rar等;
  • fileSet:拷贝文件,本示例主要有bin文件、classes文件需要拷贝;
  • dependencySets:依赖jar,拷贝到lib目录;

执行mvn package后形成了将得到如下结构:

执行mvn package后形成的结构

将该目录通过自动部署抽包并部署到宿主机器即可。然后自动部署系统执行bin下的启停脚本执行即可。

启动类

public class Bootstrap { 
  public static void main(String[] args) throws Exception { 
      ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring-config.xml"); 
      ctx.registerShutdownHook(); 
      Thread.currentThread().join(); 
  } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

本示例没有使用Java Config方式构建,直接加载spring配置文件启动Java应用。

启动脚本

#!/bin/sh 
echo ------------------------------------------- 
echo start server 
echo ------------------------------------------- 
# 设置项目代码路径 
export CODE_HOME="/export/App/nonweb-example-startup-package" 
#日志路径 
export LOG_PATH="/export/Logs/nonweb.example.jd.local" 
mkdir -p $LOG_PATH 
# 设置依赖路径 
export CLASSPATH="$CODE_HOME/classes:$CODE_HOME/lib/*" 
# java可执行文件位置 
export _EXECJAVA="$JAVA_HOME/bin/java" 
# JVM启动参数 
export JAVA_OPTS="-server -Xms128m -Xmx256m -Xss256k -XX:MaxDirectMemorySize=128m" 
# 启动类 
export MAIN_CLASS=com.jd.nonweb.example.startup.Bootstrap 
 
$_EXECJAVA $JAVA_OPTS -classpath $CLASSPATH $MAIN_CLASS & 
tail -f $LOG_PATH/stdout.log 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

配置项目代码路径、日志路径、依赖路径、java执行文件路径、JVM启动参数、启动类。

停止脚本

#日志路径 
export LOG_PATH="/export/Logs/nonweb.example.jd.local" 
mkdir -p $LOG_PATH 
# 启动类 
export MAIN_CLASS=com.jd.nonweb.example.startup.Bootstrap 
 
echo ------------------------------------------- 
echo stop server 
 
#所有相关进程 
PIDs=`jps -l | grep $MAIN_CLASS | awk '{print $1}'` 
#停止进程 
if [ -n "$PIDs" ]; then 
  for PID in $PIDs; do 
      kill $PID 
      echo "kill $PID" 
  done 
fi 
 
#等待50秒 
for i in 1 10; do 
  PIDs=`jps -l | grep $MAIN_CLASS | awk '{print $1}'` 
  if [ ! -n "$PIDs" ]; then 
    echo "stop server success" 
    echo ------------------------------------------- 
    break 
  fi 
  echo "sleep 5s" 
  sleep 5 
done 
 
#如果等待50秒还没有停止完,直接杀掉 
PIDs=`jps -l | grep $MAIN_CLASS | awk '{print $1}'` 
if [ -n "$PIDs" ]; then 
  for PID in $PIDs; do 
      kill -9 $PID 
      echo "kill -9 $PID" 
  done 
fi 
tail -fn200 $LOG_PATH/stdout.log 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.

到此一个闭环非web应用就构建完了,启停脚本、启动类、项目代码都是统一在一处维护,并使用maven-assembly-plugin将这些打包在一起,通过自动部署发布并执行,达到了闭环的目的。

从零构建web应用

项目结构

从零构建web应用 项目结构

maven依赖(pom.xml)

需要自己添加如spring-core、spring-context、spring-web、spring-webmvc、velocity等相关依赖,此处就不展示了。

打包配置(pom.xml)

web-example\pom.xml

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-assembly-plugin</artifactId> 
    <version>2.6</version> 
    <configuration> 
        <descriptor>src/assembly/assembly.xml</descriptor> 
        <finalName>${project.build.finalName}</finalName> 
    </configuration> 
    <executions> 
        <execution> 
            <phase>package</phase> 
            <goals> 
                <goal>directory</goal> 
            </goals> 
        </execution> 
    </executions> 
</plugin> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

使用maven-assembly-plugin进行打包;打包配置如下:

<id>package</id> 
<formats> 
    <format>dir</format> 
</formats> 
<includeBaseDirectory>false</includeBaseDirectory> 
<fileSets> 
    <fileSet> 
        <directory>src/bin</directory> 
        <outputDirectory>bin</outputDirectory> 
        <includes> 
            <include>*.sh</include> 
        </includes> 
        <lineEnding>unix</lineEnding> 
        <fileMode>0755</fileMode> 
    </fileSet> 
    <!-- WEB-INF --> 
    <fileSet> 
        <directory>src/main/webapp</directory> 
        <outputDirectory></outputDirectory> 
    </fileSet> 
    <!-- classes --> 
    <fileSet> 
        <directory>${project.build.directory}/classes</directory> 
        <outputDirectory>WEB-INF/classes</outputDirectory> 
    </fileSet> 
 
</fileSets> 
<!-- 依赖jar包 --> 
<dependencySets> 
    <dependencySet> 
        <outputDirectory>WEB-INF/lib</outputDirectory> 
        <excludes> 
            <exclude>com.jd:web-example</exclude> 
        </excludes> 
    </dependencySet> 
</dependencySets> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

 

 

 

主要有三组配置:

  • formats:打包格式,此处使用的是dir,还可以是zip、rar等;
  • fileSet:拷贝文件,本示例主要有bin文件、classes文件、webapp文件需要拷贝;
  • dependencySets:依赖jar,拷贝到WEB-INF\lib目录;

执行mvn package后形成了将得到如下结构:

执行mvn package后形成的结构

打包的目录结构和普通web结构完全一样;将该目录通过自动部署抽包并发布到宿主机器即可。然后自动部署系统执行bin下的启停脚本执行即可。

启动类

public class TomcatBootstrap { 
  private static final Logger LOG = LoggerFactory.getLogger(TomcatBootstrap.class); 
  public static void main(String[] args) throws Exception{ 
    //提升性能(https://wiki.apache.org/tomcat/HowTo/FasterStartUp) 
    System.setProperty("tomcat.util.scan.StandardJarScanFilter.jarsToSkip", "*.jar"); 
    //System.setProperty("securerandom.source","file:/dev/./urandom"); 
    int port =Integer.parseInt(System.getProperty("server.port", "8080")); 
    String contextPath = System.getProperty("server.contextPath", ""); 
    String docBase = System.getProperty("server.docBase", getDefaultDocBase()); 
    LOG.info("server port : {}, context path : {},doc base : {}",port, contextPath, docBase); 
    Tomcat tomcat = createTomcat(port,contextPath, docBase); 
    tomcat.start(); 
     Runtime.getRuntime().addShutdownHook(new Thread() { 
        @Override 
        public void run(){ 
            try { 
                tomcat.stop(); 
            } catch (LifecycleException e) { 
                LOG.error("stoptomcat error.", e); 
            } 
        } 
    }); 
    tomcat.getServer().await(); 
  } 
 
  private static String getDefaultDocBase() { 
   File classpathDir = new File(Thread.currentThread().getContextClassLoader().getResource(".").getFile()); 
   File projectDir =classpathDir.getParentFile().getParentFile(); 
   return new File(projectDir,"src/main/webapp").getPath(); 
  } 
 private static Tomcat createTomcat(int port,String contextPath, String docBase) throws Exception{ 
    String tmpdir = System.getProperty("java.io.tmpdir"); 
    Tomcat tomcat = new Tomcat(); 
    tomcat.setBaseDir(tmpdir); 
    tomcat.getHost().setAppBase(tmpdir); 
    tomcat.getHost().setAutoDeploy(false); 
    tomcat.getHost().setDeployOnStartup(false); 
    tomcat.getEngine().setBackgroundProcessorDelay(-1); 
    tomcat.setConnector(newNioConnector()); 
    tomcat.getConnector().setPort(port); 
    tomcat.getService().addConnector(tomcat.getConnector());  
    Context context =tomcat.addWebapp(contextPath, docBase); 
    StandardServer server =(StandardServer) tomcat.getServer(); 
    //APR library loader. Documentation at /docs/apr.html 
    server.addLifecycleListener(new AprLifecycleListener()); 
    //Prevent memory leaks due to use of particularjava/javax APIs 
    server.addLifecycleListener(new JreMemoryLeakPreventionListener()); 
    return tomcat; 
  } 
 
  //在这里调整参数优化 
  private static Connector newNioConnector() { 
    Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); 
    Http11NioProtocol protocol =(Http11NioProtocol) connector.getProtocolHandler(); 
    return connector; 
  } 
 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.

通过嵌入Tomcat容器启动,这种方式的确定是需要先写Tomcat的启动代码,优点也很明显:以后Tomcat的控制权在我们手中,可以随时进行切换或者优化,不需要改线上的配置文件。

启动脚本

#!/bin/sh 
echo ------------------------------------------- 
echo start server 
echo ------------------------------------------- 
# 设置项目代码路径 
export CODE_HOME="/export/App/web-example-web-package" 
#日志路径 
export LOG_PATH="/export/Logs/web.example.jd.local" 
mkdir -p $LOG_PATH 
# 设置依赖路径 
export CLASSPATH="$CODE_HOME/WEB-INF/classes:$CODE_HOME/WEB-INF/lib/*" 
# java可执行文件位置 
export _EXECJAVA="$JAVA_HOME/bin/java" 
# JVM启动参数 
export JAVA_OPTS="-server -Xms128m -Xmx256m -Xss256k-XX:MaxDirectMemorySize=128m" 
# 服务端端口、上下文、项目根配置 
export SERVER_INFO="-Dserver.port=8090 -Dserver.contextPath=-Dserver.docBase=$CODE_HOME" 
# 启动类 
export MAIN_CLASS=com.jd.web.example.startup.TomcatBootstrap 
 
$_EXECJAVA $JAVA_OPTS -classpath $CLASSPATH $SERVER_INFO $MAIN_CLASS & 
tail -f $LOG_PATH/stdout.log 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

配置项目代码路径、日志路径、依赖路径、java执行文件路径、JVM启动参数、启动类;相当于非web应用,多了web服务器端口、上下文、项目根路径配置。

停止脚本

和非web的类似就不再重复了。

到此一个闭环web应用就构建完了,启停脚本、启动类、项目代码都是统一在一处维护,并使用maven-assembly-plugin将这些打包在一起,通过自动部署发布并执行。达到了闭环的目的。

Spring Boot构建非web/web应用

项目结构

Spring Boot构建非web/web应用  项目结构

maven依赖(pom.xml)

spring-boot-example/pom.xml继承spring-boot-starter-parent

<parent> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-parent</artifactId> 
    <version>1.4.1.BUILD-SNAPSHOT</version> 
</parent> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

spring-boot-starter-parent中是一些通用配置,如JDK编码、依赖管理(它又继承了spring-boot-dependencies,这里边定义了所有依赖);

依赖

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-web</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-velocity</artifactId> 
</dependency> 
<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-log4j2</artifactId> 
</dependency> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

spring-boot-starter是最小化的spring boot环境(spring-core、spring-context等);spring-boot-starter-web是spring mvc环境,并使用Tomcat作为web容器;spring-boot-starter-velocity将自动将模板引擎配置为velocity。此处可以看到starter的好处了,需要什么功能只需要引入一个starter,相关的依赖自动添加,而且会自动配置使用该特性。

打包配置(pom.xml)

spring-boot-example-web\pom.xml添加如下maven插件:

<plugin> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-maven-plugin</artifactId> 
</plugin> 
  • 1.
  • 2.
  • 3.
  • 4.

执行mvn package时将得到如下fat jar:

执行mvn package时将得到如下fat jar

启动类

package com.jd.springboot.example.web.startup; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.context.annotation.ImportResource; 
@SpringBootApplication(scanBasePackages = "com.jd.springboot.example"
@ImportResource("classpath:spring-config.xml") 
public class Bootstrap { 
  public static void main(String[] args) { 
      SpringApplication.run(Bootstrap.class, args); 
  } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

@SpringBootApplication指定了要扫描的包、可以使用@ImportResource引入xml配置文件。然后可以直接作为普通java应用启动即可,此时自动使用tomcat作为web容器启动。

运行 jar -jar spring-boot-example-1.0-SNAPSHOT.jar即可启动(META-INF\MANIFEST.MF指定了Main-Class)。

个人不太喜欢fat jar的方式。可以使用maven-assembly-plugin配合来打包Java应用。项目结构如下所示:

使用maven-assembly-plugin配合来打包Java应用

项目结构和之前的区别是多了assembly和bin。

打包配置(pom.xml)

spring-boot-example-web\pom.xml将如下maven插件

<plugin> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-maven-plugin</artifactId> 
</plugin> 
  • 1.
  • 2.
  • 3.
  • 4.

更改为assembly插件

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-assembly-plugin</artifactId> 
    <version>2.6</version> 
    <configuration> 
        <descriptor>src/assembly/assembly.xml</descriptor> 
        <finalName>${project.build.finalName}</finalName> 
    </configuration> 
    <executions> 
        <execution> 
            <phase>package</phase> 
            <goals> 
                <goal>directory</goal> 
            </goals> 
        </execution> 
    </executions> 
</plugin> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

assembly.xml和“从零构建非web应用”的类似,就不贴配置了。

执行mvn package时将得到如下打包:

执行mvn package时得到的打包

启停脚本也是类似的,在此也不贴配置了。到此基于spring boot的非fat jar方式的自启动Java应用就构建好了。

总结

从零构建非web应用/web应用需要我们查找相关依赖并配置,还需要进行一些配置(Spring配置、容器配置),如果构建一个新的项目还是相对较慢的,但是在公司内大家应该都有自己的“starter pom”,因此实际构建也不会很慢。而如果没有一些项目的积累,使用spring boot可以非常容易而且快速的就能搭建出想要的项目。使用spring boot后:容易添加依赖、启动类不用自己创建、享受到自动配置的好处等;而自带的spring-boot-maven-plugin会生成fat jar,不过可以配合maven-assembly-plugin来实现之前的方式的。

另外因笔者所在公司使用Docker容器,一个宿主机器只部署一个JVM示例,示例中的启停脚本不用考虑单机多JVM实例问题。

创建闭环Java应用,可以更容易的进行如JVM参数调优、修改容器配置文件、非web应用不需要部署到Tomcat容器中;这是笔者想进行闭环Java应用的主要目的。

【本文是51CTO专栏作者张开涛的原创文章,作者微信公众号:开涛的博客( kaitao-1234567)】

责任编辑:赵宁宁 来源: 开涛的博客
相关推荐

2022-10-08 06:49:32

LinuxWindows操作系统

2024-12-06 09:47:13

2023-05-08 08:03:10

2023-10-26 21:41:45

云计算企业云基础

2023-10-19 15:25:40

2024-06-05 09:22:43

2017-01-15 18:32:39

Openresty架构性能

2021-02-23 10:42:45

AI

2022-02-08 11:31:23

Linux端口命令

2022-01-13 09:58:26

Linux端口命令

2017-02-17 07:46:29

2018-08-21 05:12:10

2024-01-02 07:34:38

CentOSLinuxRedhat

2020-12-18 06:09:07

Java浅拷贝深拷贝

2015-06-15 11:05:13

DCIM数据中心

2020-04-14 12:12:20

JavaScriptIIFE函数

2013-06-05 13:49:41

EclipseIntelliJ

2022-09-21 10:54:49

无线Wi-Fi 6

2023-02-21 10:51:49

2016-05-18 14:00:24

点赞
收藏

51CTO技术栈公众号