SpringBoot test deployment

Original: https://zhuanlan.zhihu.com/p/26794187

Many netizens will ask me from time to time, how to test the spring boot project, how to deploy, is there any good deployment plan in production? This article will introduce how spring boot is developed, debugged, packaged and put into production.

development stage

unit test

The most important thing in the development phase is unit testing, and springboot's support for unit testing is already very complete.

1. Add the spring-boot-starter-test package reference to the pom package


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

2. Development and testing class

Taking the simplest helloworld as an example, you need to add @RunWith(SpringRunner.class) and @SpringBootTest annotations to the class header of the test class, add @Test to the top of the test method, and finally right-click on the method to run run.


@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

    @Test
    public void hello() {
        System.out.println("hello world");
    }

}

In actual use, you can inject the dao layer code or the service layer code for testing and verification according to the normal use of the project. spring-boot-starter-test provides many basic usages, and even more rare is the addition of support for Controller layer testing.


//简单验证结果集是否正确
Assert.assertEquals(3, userMapper.getAll().size());

//验证结果集,提示
Assert.assertTrue("错误,正确的返回值为200", status == 200); 
Assert.assertFalse("错误,正确的返回值为200", status != 200);  

The introduction of MockMvc supports the testing of the Controller layer. A simple example is as follows:


public class HelloControlerTests {

    private MockMvc mvc;

    //初始化执行
    @Before
    public void setUp() throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(new HelloController()).build();
    }

    //验证controller是否正常响应并打印返回结果
    @Test
    public void getHello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }

    //验证controller是否正常响应并判断返回结果是否正确
    @Test
    public void testHello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Hello World")));
    }

}

Unit testing is the first barrier to verifying your code. It is necessary to develop the habit of unit testing every time you write a part of the code. Don't wait until all the integration is completed before testing. After integration, because you pay more attention to the overall operation effect, it is easy to miss the bottom layer of the code. bug.

Integration Testing

After the overall development is completed, enter the integration test. The startup entry of the spring boot project is in the Application class, and the project can be started directly by running the run method. However, during the debugging process, we must constantly debug the code. It is very troublesome to restart a service manually. Spring boot provides support for hot deployment very intimately, which is very convenient for debugging and use in web projects.

pom needs to add the following configuration:


 <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork>
            </configuration>
        </plugin>
</plugins>
</build>

After adding the above configuration, the project supports hot deployment, which is very convenient for integration testing.

put into production online

In fact, I think this stage should be relatively simple and generally divided into two types; one is packaged into a jar package for direct execution, and the other is packaged into a war package and placed under the tomcat server.

Typed into a jar package

如果你使用的是maven来管理项目,执行以下命令既可以


cd 项目跟目录(和pom.xml同级)
mvn clean package
## 或者执行下面的命令
## 排除测试代码后进行打包
mvn clean package  -Dmaven.test.skip=true

打包完成后jar包会生成到target目录下,命名一般是 项目名+版本号.jar

启动jar包命令


java -jar  target/spring-boot-scheduler-1.0.0.jar

这种方式,只要控制台关闭,服务就不能访问了。下面我们使用在后台运行的方式来启动:


nohup java -jar target/spring-boot-scheduler-1.0.0.jar &

也可以在启动的时候选择读取不同的配置文件


java -jar app.jar --spring.profiles.active=dev

gradle
如果使用的是gradle,使用下面命令打包


gradle build
java -jar build/libs/mymodule-0.0.1-SNAPSHOT.jar

打成war包


打成war包一般可以分两种方式来实现,第一种可以通过eclipse这种开发工具来导出war包,另外一种是使用命令来完成,这里主要介绍后一种

1、maven项目,修改pom包


<packaging>jar</packaging>  

改为


<packaging>war</packaging>

2、打包时排除tomcat.


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

在这里将scope属性设置为provided,这样在最终形成的WAR中不会包含这个JAR包,因为Tomcat或Jetty等服务器在运行时将会提供相关的API类。

3、注册启动类

创建ServletInitializer.java,继承SpringBootServletInitializer ,覆盖configure(),把启动类Application注册进去。外部web应用服务器构建Web Application Context的时候,会把启动类添加进去。


public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
}

最后执行


mvn clean package  -Dmaven.test.skip=true

会在target目录下生成:项目名+版本号.war文件,拷贝到tomcat服务器中启动即可。

gradle

如果使用的是gradle,基本步奏一样,build.gradle中添加war的支持,排除spring-boot-starter-tomcat:


...

apply plugin: 'war'

...

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:1.4.2.RELEASE"){
        exclude mymodule:"spring-boot-starter-tomcat"
    }
}
...

再使用构建命令


gradle build

war会生成在build\libs 目录下。

生产运维

查看JVM参数的值

可以根据java自带的jinfo命令:


jinfo -flags pid

来查看jar 启动后使用的是什么gc、新生代、老年代分批的内存都是多少,示例如下:


-XX:CICompilerCount=3 -XX:InitialHeapSize=234881024 -XX:MaxHeapSize=3743416320 -XX:MaxNewSize=1247805440 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=78118912 -XX:OldSize=156762112 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC
  • -XX:CICompilerCount :最大的并行编译数
  • -XX:InitialHeapSize 和 -XX:MaxHeapSize :指定JVM的初始和最大堆内存大小
  • -XX:MaxNewSize : JVM堆区域新生代内存的最大可分配大小
  • ...
  • -XX:+UseParallelGC :垃圾回收使用Parallel收集器

如何重启

简单粗暴

直接kill掉进程再次启动jar包


ps -ef|grep java 
##拿到对于Java程序的pid
kill -9 pid
## 再次重启
Java -jar  xxxx.jar

当然这种方式比较传统和暴力,所以建议大家使用下面的方式来管理

脚本执行

如果使用的是maven,需要包含以下的配置


<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <executable>true</executable>
    </configuration>
</plugin>

如果使用是gradle,需要包含下面配置


springBoot {
    executable = true
}

做一个软链接指向你的jar包并加入到init.d中或者将jar包封装成一个服务来管理。

init.d 例子:


$ln -s /var/yourapp/yourapp.jar /etc/init.d/yourapp

这样就可以使用stop或者是restart命令去管理你的应用。


$/etc/init.d/yourapp start|stop|restart

或者添加脚本,将jar包注册为服务


[Unit]
Description=yourapp
After=syslog.target

[Service]
ExecStart=/var/yourapp/yourapp.jar

[Install]
WantedBy=multi-user.target

到此 springboot项目如何测试、联调和打包投产均已经介绍完,以后可以找时间研究一下springboot的自动化运维,以及spring boot 和docker相结合的使用。


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324501433&siteId=291194637