Art is long, life is long

preface

How is the Spring Boot project tested, how is it deployed, and is there a good deployment plan in production?

This article describes how Spring Boot is developed, debugged, packaged, and finally launched.

The development phase

Unit testing

Unit testing is the most important part of the development phase, and Spring Boot already has great support for unit testing.

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>
Copy the code

2. Develop test classes

Take the simplest HelloWorld as an example, add @runWith (springrunner.class) and @SpringbooTtest annotations to the header of the Test class. Add @test at the top of the Test method, and finally right-click on the method to run.

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

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

In practice, it is possible to inject data layer code or Service layer code for testing validation as normal for the project. Spring-boot-starter-test provides many basic uses, but it also adds support for Controller layer testing.

// Simply verify that the result set is correct
Assert.assertEquals(3, userMapper.getAll().size());

// Validate result set, prompt
Assert.assertTrue("Error, the correct return value is 200", status == 200); 
Assert.assertFalse("Error, the correct return value is 200", status ! =200);  
Copy the code

MockMvc was introduced to support testing of the Controller layer, as shown in the following simple example:

public class HelloControlerTests {

    private MockMvc mvc;

    // Initialize the execution
    @Before
    public void setUp(a) throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(new HelloController()).build();
    }

    // Verify that the controller is responding properly and print the result
    @Test
    public void getHello(a) throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }
    
    // Verify that the controller responds properly and that the result returned is correct
    @Test
    public void testHello(a) throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Hello World"))); }}Copy the code

Unit testing is the first barrier to verifying your code. Get into the habit of unit testing every part of your code. Don’t wait until the integration is complete.

Integration testing

After the completion of the overall development, we enter the integration test. The startup entrance of the Spring Boot project is in the Application class. We can directly run the run method to start the project, but during the debugging process, we definitely need to constantly debug the code. Spring Boot is very considerate to provide hot deployment support, easy to use in Web projects debugging.

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>
Copy the code

By adding the above configuration, the project supports hot deployment, making integration testing very convenient.

Production of online

Actually, I think it’s a little bit easier at this stage and there are two kinds of things; One is packaged as a JAR package and executed directly, the other is packaged as a WAR package and placed under the Tomcat server.

Into the jar package

If you are using Maven to manage projects, execute the following command

CD Project and directory (the same level as pom.xml) MVN cleanpackagePackage MVN clean after removing the test codepackage  -Dmaven.test.skip=true
Copy the code

After the package is completed, the jar package will be generated in the target directory, and the name is usually the project name + version number. Jar

Start jar package command

java -jar  target/spring-boot-scheduler-1.0. 0.jar
Copy the code

This way, once the console is closed, the service is not accessible. Here we use in the background to start:

nohup java -jar target/spring-boot-scheduler-1.0. 0.jar &
Copy the code

You can also choose to read a different configuration file at startup

java -jar app.jar --spring.profiles.active=dev
Copy the code

JVM parameters can also be set at startup time

java -Xms10m -Xmx80m -jar app.jar &
Copy the code

Gradle If you are using Gradle, use the following command to package

gradle build
java -jar build/libs/mymodule-0.01.-SNAPSHOT.jar
Copy the code

Into the war package

There are two ways to create a WAR package. The first way is to export a war package through a development tool like Eclipse, and the other way is to use commands to do it

1. Maven project, modify poM package

will

<packaging>jar</packaging>  
Copy the code

Instead of

<packaging>war</packaging>
Copy the code

2. Exclude Tomcat from packaging.

<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>
Copy the code

By setting the Scope property to Provided, the JAR package will not be included in the resulting WAR, since servers such as Tomcat or Jetty will provide the associated API classes at runtime.

3. Register the startup class

Create ServletInitializer. Java, inheritance SpringBootServletInitializer, covering the configure (), to start the class Application registered in. When the external Web Application server builds the Web Application Context, it adds the startup class to it.

public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        returnapplication.sources(Application.class); }}Copy the code

The last execution

mvn clean package  -Dmaven.test.skip=true
Copy the code

War file will be generated in the target directory. Copy it to the Tomcat server and start it.

gradle

If you are using Gradle, add war support to build. Gradle and exclude spring-boot-starter-tomcat:

. apply plugin:'war'. dependencies { compile("Org. Springframework. The boot: spring - the boot - starter - web: 1.4.2. RELEASE"){
    	exclude mymodule:"spring-boot-starter-tomcat"}}...Copy the code

Then use the build command

gradle build
Copy the code

The war will be generated in the build\libs directory.

Production operations

View the values of the JVM parameters

You can use the Java jinfo command:

jinfo -flags pid
Copy the code

To see what gc, generation, and generation batch memory are used after jar startup, as shown in the following example:

-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
Copy the code
  • -XX:CICompilerCount : Indicates the maximum number of parallel compilations
  • -XX:InitialHeapSize-XX:MaxHeapSize: Specifies the initial and maximum heap size for the JVM
  • -XX:MaxNewSize: The maximum allocatable size of new generation memory in the JVM heap region
  • -XX:+UseParallelGCParallel collector is used for garbage collection

How to restart

Simple and crude

Kill the process and start the JAR package again

Ps - ef | grep Java # # to get the pid kill for Java program9Pid ## Restart Java -jar xxxx.jar againCopy the code

Of course, this way is more traditional and violent, so I suggest you use the following way to manage

Script execution

If you are using Maven, you need to include the following configuration

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

If you are using Gradle, you need to include the following configuration

springBoot {
    executable = true
}
Copy the code

Startup mode:

1. You can start it directly from./yourapp.jar

2. Register as a service

You can also make a soft link to your jar package and add it to init.d, then start it with a command.

Example: d init.

ln -s /var/yourapp/yourapp.jar /etc/init.d/yourapp
chmod +x /etc/init.d/yourapp
Copy the code

This allows you to use the stop or restart command to manage your application.

/etc/init.d/yourapp start|stop|restart
Copy the code

or

service yourapp start|stop|restart
Copy the code

So far, how to test, tune and package the Spring Boot project into production has been introduced.