spring-boot 入门

一、maven构建

1.1 继承boot超级parent

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.1.RELEASE</version>
</parent>

这样,其他依赖不需要写版本号,如果一定要写,配置在properties即可,如:

<properties>
    <spring-data-releasetrain.version>Fowler-SR2</spring-data-releasetrain.version>
</properties>

默认版本号可以在下面配置找到:
https://github.com/spring-projects/spring-boot/blob/v1.4.1.RELEASE/spring-boot-dependencies/pom.xml

1.2 不继承parent

如果不继承parent,可以使用一下配置完成:

<dependencyManagement>
     <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.4.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

但是,不能在properties特殊指定版本,如果需要,可以在生dependencyManagement并列添加对应依赖;

例如:

<dependencyManagement>
    <dependencies>
        <!-- Override Spring Data release train provided by Spring Boot -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-releasetrain</artifactId>
            <version>Fowler-SR2</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.4.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

1.3 指定jdk版本

<properties>
    <java.version>1.8</java.version>
</properties>

1.4 打包

添加以下配置后,会生成一个可执行jar包

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

1.5 俩个常用包

spring-boot-starter-actuator:管理配置和监控
spring-boot-starter-remote-shell:远程shell

二、代码结构

com
 +- example
     +- myproject
         +- Application.java
         |
         +- domain
         |   +- Customer.java
         |   +- CustomerRepository.java
         |
         +- service
         |   +- CustomerService.java
         |
         +- web
             +- CustomerController.java

Application.java:启动类

package com.example.myproject;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@SpringBootApplication可以代替上面三个注解;
@ComponentScan:默认只扫描main下面的包,方便起见,最好是自己配@ComponentScan(«com.henry.exameple»)
@ImportResource:引入xml配置文件

三、启动和部署

3.1 开发启动

  1. 运行main方法
  2. 执行jar包:
    java -jar target/myproject-0.0.1-SNAPSHOT.jar
  3. 远程调试:

    java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -jar target/myproject-0.0.1-SNAPSHOT.jar
    

    3.2 热启动

3.2.1 添加依赖

添加以下依赖,当代码变动时,它会自动进行重启应用
> 注:这个插件会导致dubbo调用失败,具体原因未查)

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

或者使用springloaded插件来实现,这种情况下,只有debug时自动加载。

<build>
    <plugins>
        <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <dependencies>
                	<dependency>
	                    <groupId>org.springframework</groupId>
	                    <artifactId>springloaded</artifactId>
	                    <version>1.2.1.RELEASE</version>
                	</dependency>
                </dependencies>
            </plugin>
    </plugins>
</build>

3.2.2 IDE 自动加载

  • eclipse:保存文件即可
  • idea:BuildMake Project

:使用java -jar 启动时,自动认为是生产环境,自动重启/加载将会失效。

3.2.3 配置

  1. 排除自动加载路径
    spring.devtools.restart.exclude=static/**,public/**
  2. 如果不希望每次保存文件都启动,可以通过trigger-file

    spring.devtools.restart.trigger-file
    

    3.2.3 关闭restart

    application.properties

    spring.devtools.restart.enabled = false
    

    3.2.4 美化配置

  3. 在resources下添加banner.txt,里面的内容将在启动时输出

  4. 实现org.springframework.boot.ExitCodeGenerator可以自定义应用关闭时的返回

3.3 生产环境部署

3.3.1 init.d 启停

spring boot可以直接用nohup jar -jar myqpp.jar >/dev/null 2>&1 &
但是不好优雅stop,在有acutor时,可以通过如下方式
1.Maven pom.xml:

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

2.application.properties:

endpoints.shutdown.sensitive=false
endpoints.shutdown.enabled=true

3.Send a post method to shutdown the app:

curl -X POST localhost:port/shutdown

但是不方便,推荐init.d。
启停可以自己写脚本实现,spring boot init.d服务,只要jar包是通过spring-boot-maven-plugin打包。

ln -s /var/myapp/myapp.jar /etc/init.d/myapp
service myapp start|stop|restart
  • PID文件:/var/run/appname/appname.pid
  • 启动日志:/var/log/appname.log

调整JVM启动参数:
新建一个同名.conf文件。
myapp.conf

JAVA_OPTS=-Xmx1024M
LOG_FOLDER=/custom/log/folder

个性化调整,可以配置

四、spring-boot配置

4.1 application.properties

详细见github
https://github.com/ErDaoYa/spring-learn/blob/master/spring-boot/application.properties

4.2 环境相关配置

可以定义application-dev.properties,在启动时加载,application.properties,没有的配置,继续沿用。

java -jar target/***.jar --spring.profiles.active=dev

还可以直接指定配置文件启动

java -jar  ***.jar --spring.config.name=myproject

五、个性化

5.1 处理错误页面

public class ContainerConfig {
    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer(){
        return new MyCustomizer();
    }
    private static class MyCustomizer implements EmbeddedServletContainerCustomizer {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {
            container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/500"));
        }
    }
@RestController
public class ExceptionController {
    @RequestMapping("/exception")
    public void catchException() {
        throw new RuntimeException("error occur");
    }

    @RequestMapping("/500")
    public void showServerError() {
        throw new C403Exception("资源不可用",null);
    }
}

5.2 MessageConverters个性化配置

4.2.1 自带Jackson配置

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
/**
 * <p>jackson个性化配置</p>
 * @author zhaozhou
 * Created on 2016/10/31.
 */
@Configuration
public class Jackson2HttpMessageConverter extends WebMvcConfigurerAdapter {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(createFastJsonHttpMessageConverter());
        super.configureMessageConverters(converters);
    }
    private MappingJackson2HttpMessageConverter createFastJsonHttpMessageConverter() {
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        jsonConverter.setObjectMapper(objectMapper);
        return jsonConverter;
    }
}

4.2.1 扩展fastjson

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.ArrayList;
import java.util.List;
/**
 * <p>fastjson配置类</p>
 * @since 1.0
 */
@Configuration
//@EnableWebMvc
public class FastJsonHttpMessageConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(createFastJsonHttpMessageConverter());
        super.configureMessageConverters(converters);
    }
    private FastJsonHttpMessageConverter4 createFastJsonHttpMessageConverter() {

        //spring mvc 4x 应该使用FastJsonHttpMessageConverter4
        FastJsonHttpMessageConverter4 fastJsonHttpMessageConverter4= new FastJsonHttpMessageConverter4();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();

        //特色配置
        fastJsonConfig.setSerializerFeatures(
//                SerializerFeature.PrettyFormat,/
                SerializerFeature.DisableCircularReferenceDetect, //关闭引用支持
                SerializerFeature.BrowserCompatible,
                SerializerFeature.SkipTransientField,
                SerializerFeature.QuoteFieldNames
        );
        fastJsonHttpMessageConverter4.setFastJsonConfig(fastJsonConfig);

        //属性过滤器
     /*   PropertyFilter filter = new PropertyFilter() {
            public boolean apply(Object source, String name, Object value) {
                if (null == name) {
                    return false;
                }
                return true;
            }
        };*/
//        fastJsonConfig.setSerializeFilters(filter);

        // 设置MediaTypes
        List<MediaType> mediaTypes =new ArrayList<MediaType>();
        mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        fastJsonHttpMessageConverter4.setSupportedMediaTypes(mediaTypes);
        return fastJsonHttpMessageConverter4;
    }
}

5.3 静态文件目录和欢迎页设置

同样在config中重写addResourceHandlersaddViewControllers方法;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter
{
    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
            "classpath:/dist/", "classpath:/public/" };
    // @Value("${property:default value}")
    @Value("${dubbor.web.welcome-file:index.html}")
    private String welcomeFile;
    ...
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!registry.hasMappingForPattern("/webjars/**")) {
        registry.addResourceHandler("/webjars/**").addResourceLocations(
                "classpath:/META-INF/resources/webjars/");
    }
    if (!registry.hasMappingForPattern("/**")) {
        registry.addResourceHandler("/**").addResourceLocations(
                CLASSPATH_RESOURCE_LOCATIONS);
    }
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
    if(!StringUtils.isEmpty(welcomeFile) || !"index.html".equals(welcomeFile)){
        registry.addViewController("/").setViewName("forward:"+welcomeFile);
        registry.setOrder( Ordered.HIGHEST_PRECEDENCE );
    }
    super.addViewControllers( registry );
}
CONTENTS