springboot 03 Spring Boot Features

Part IV. Spring Boot Features(Spring Boot 的特性)SpringApplication
通常放在了main函数中,作为spring-boot的启动类

public static void main(String[] args) {
    SpringApplication.run(MySpringConfiguration.class, args);
}
1. Customizing the Banner(自定义Banner)

Banner将会在系统启动的时候打印出来,4中方式设置
在classpath中添加一个文件banner.txt
通过参数banner.location来设置文件的位置,设置文件的编码banner.charset(默认使用UTF-8)
在classpath中添加一个文件banner.gif, banner.jpg or banner.png
通过参数banner.image.location来设置图片文件的位置
在banner.txt文件中可以设置下面的参数:
${application.version}
${application.formatted-version}
${spring-boot.version}
${spring-boot.formatted-version}
${application.title}
通过程序来设置banner
实现这个接口中org.springframework.boot.Banner 的printBanner()方法,在通过SpringApplication.setBanner(…)来设置自己实现的Banner
也可以使用spring.main.banner-mode来设置是否启用或者关闭打印banner功能,可选参数log,off

2. Customizing SpringApplication

通常使用SpringApplication的静态方法运行,为了设置更多的参数,可以直接new一个SpringApplication

public static void main(String[] args) {
    SpringApplication app = new SpringApplication(MySpringConfiguration.class);
    app.setBannerMode(Banner.Mode.OFF);
    app.run(args);
}

虽然可以通过编程的方式来实现配置参数,但是官方建议使用application.properites来配置。更多配置参数参考SpringApplication Javadoc

3. Application events and listeners

顺序如下: ApplicationStartedEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ApplicationReadyEvent,ApplicationFailedEvent

使用SpringApplication.addListeners(…)添加事件监听器

4. Accessing application arguments(访问application的参数)

可以依赖注入org.springframework.boot.ApplicationArguments,ApplicationArguments提供了访问application参数的方法;
也可以直接把需要的参数作为属性,使用@Value来访问

5. Using the ApplicationRunner or CommandLineRunner

如果想要在SpringApplication.run(...)执行完成前对参数做一些特殊处理,可以使用ApplicationRunner,CommandLineRunner这两个接口

@Component
public class MyBean implements CommandLineRunner {
    public void run(String... args) {
        // Do something...
    }
}
6. Application exit

所有Spring管理的类在结束之前需要做一些事,可以使用DisposableBean接口或者@PreDestroy注解,
如果需要在Application容器结束后返回一些特殊的Code,可以实现org.springframework.boot.ExitCodeGenerator 接口


Externalized Configuration

1. Application property files

Spring-boot会从application.properties中寻找配置属性,application.properties可以放在如下位置:
放在当前项目根目录下
放在当前项目根目录下的/config中
放在classpath根目录下(推荐)
放在claasspath根目录下/config中
注意:目录最深的覆盖上层的熟悉
也可以通过spring.config.name,spring.config.location在命令行参数中指定参数文件的名字和加载位置

2. Profile-specific properties

通常我们需要对测试环境,开发环境,正式环境配置不同的参数,我们可以写多个配置文件,
格式 application-{profile}.properties,然后再applicatioin.properties中使用spring.profiles.active来指定使用哪一个或多个配置文件(多个文件使用逗号分隔),特定的配置文件中的属性将会覆盖application.propreties中的属性
也可以使用 @Profile("...") 来指定使用哪个文件

@Configuration
@Profile("production")
public class ProductionConfiguration {
    // ...
}

在application.properties中的参数可以项目使用,比如:
app.name=MyApp app.description=${app.name} is a Spring Boot application 3. Type-safe Configuration Properties
使用@Value("${property}")来依赖注入属性有时候会很麻烦,尤其是多个属性需要注入。Spring-boot提供一种更加方便的方式@ConfigurationProperties。
首先建立一个类

@ConfigurationProperties(prefix="connection")
public class ConnectionProperties {
    private String username;
    private InetAddress remoteAddress;
    // ... getters and setters
}

在@EnableConfigurationProperties中指定建立的配置类

@Configuration
@EnableConfigurationProperties(ConnectionProperties.class)
public class MyConfiguration {
}

在需要使用的类中使用@Autowired注入ConnectionProperties
另一种方式,可以不用使用EnableConfigurationProperties(ConnectionProperties.class), 直接在ConnectionProperties上添加@Component

4. Relaxed binding(简便的绑定方式)
@ConfigurationProperties(prefix="person")
public class OwnerProperties {
    private String firstName;
    public String getFirstName() {
        return this.firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
}
5. @ConfigurationProperties Validation

Spring-boot 支持使用JSR-303的方式对@ConfigurationProperties的注解类的属性进行校验,并且使用@Valid 来触发校验

@Component
@ConfigurationProperties(prefix = "connection")
public class ConnectionProperties {
    @NotEmpty
    private String userName;
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    @Valid
    private ConnectionProperties connectionProperties;
    @RequestMapping("/login")
    String login() {
        return "Login Successful!=" + connectionProperties.getUserName();
    }
}
6. @ConfigurationProperties vs. @Value
Feature @ConfigurationProperties @Value
Relaxed binding Yes No
Meta-data support Yes No
evaluation No Yes
7. Programmatically setting profiles(编程的方式来设置profiles)

你可以在application启动之前调用方法 SpringApplication.setAdditionalProfiles(…);你也可以通过使用ConfigurableEnvironment接口来实现


Logging(系统日志配置)

1. 使用不同颜色输出日志

spring.output.ansi.enabled 可选的参数 :
ALWAYS ,DETECT , NEVER 参考api supported value

2. 配置日志文件

logging.file 配置日志文件名称
logging.path 配置日志文件的路径

logging.file logging.path Example Description
(none) (none) 控制台输出
指定日志文件名 (none) my.log项目根目录下输出日志文件
(none) 指定目录 /var/log在指定目录下生成日志文件

当日志文件达到10m将会重新在新的文件中输出

3. 配置日志输出级别
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
4. 配置日志输出的格式
logging.pattern.console : 配置控制台输出格式 
logging.pattern.file : 配置日志文件输出格式

Developing web applications(开发web应用)

Spring-boot对大部分应用提供了spring mvc 自动配置。自动配置了下面一些特性:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

  • Support for serving static resources, including support for WebJars (see below).

  • Automatic registration of Converter, GenericConverter, Formatter beans.

  • Support for HttpMessageConverters (see below).

  • Automatic registration of MessageCodesResolver (see below).

  • Static index.html support.

  • Custom Favicon support.

  • Automatic use of a ConfigurableWebBindingInitializer bean (see below).
    如果你想要配置spring mvc 的一些拦截器, formatters, view controllers等等,你可以创建一个类继承于WebMvcConfigurerAdapter;例如:自己配置一个拦截器

    @Configuration
    @ComponentScan(basePackages = "com.spring.boot.controller3")
    public class WebConfigure extends WebMvcConfigurerAdapter {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LogInterceptor()).addPathPatterns("/user/**");
    }
    }

如果你想要自己实现RequestMappingHandlerMapping, RequestMappingHandlerAdapter,ExceptionHandlerExceptionResolver, 你可以自己实现WebMvcRegistrationsAdapter

1. HttpMessageConverters

Spring-boot已经包含了常用的HttpMessageConverter,比如自动转换对象为JSON或者XML;如果需要自己定义一些HttpMessageConverter,可以使用Spring-boot的HttpMessageConverters类:

@Configuration
public class MyConfiguration {
    @Bean
    public HttpMessageConverters customConverters() {
        HttpMessageConverter<?> additional = ...
        HttpMessageConverter<?> another = ...
        return new HttpMessageConverters(additional, another);
    }
}
2. Static Content(静态资源)

默认情况下Spring-boot使用的是Spring-mvc中的ResourceHttpRequestHandler来处理静态资源,默认静态资源的位置是在classpath目录下或者ServletContext根目录下的/static (or /public or /resources or/META-INF/resources);你也可以添加自己的处理方式,通过使用WebMvcConfigurerAdapter中的addResourceHandlers方法。
你也可以自己定义静态资源的位置,使用配置参数spring.resources.staticLocations
Spring-boot也支持静态资源缓存,使用版本号,参考spring-boot文档静态资源处理

3. ConfigurableWebBindingInitializer

默认Spring-boot使用的是WebBindingInitializer来初始化WebDataBinder,你可以创建自己的一个WebBindingInitializer,然后使用@Bean,那么Spring-boot将会使用自己定义的来配置Spring-mvc.参考ConfigurableWebBindingInitializer的实现。

5. Template engines

Spring-boot自动配置支持以下模板引擎:
FreeMarker
Groovy
Thymeleaf
Velocity (deprecated in 1.4)
Mustache

注意:JSP在Spring-boot中尽量避免使用,当使用内嵌的Servlet服务器的时候会有一些限制。参考文档
使用这些模板引擎,它们默认情况下都会在src/main/resources/templates目录下寻找模板。

6. Error Handling

我们可以通过使用@ControllerAdvice为一些特殊的Controller处理一些特殊的Exception

@ControllerAdvice(basePackageClasses = FooController.class)
public class FooControllerAdvice extends ResponseEntityExceptionHandler {
    @ExceptionHandler(YourException.class)
    @ResponseBody
    ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
        HttpStatus status = getStatus(request);
        return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
    }
    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }
}
7. Custom error pages

为了对不同的错误状态码显示不同不错误页面,我们可以在/error目录下面添加一个文件;这个文件可以是html,也可以是模板;文件的名称可以状态码,也可以是模板,比如:

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>
src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 5xx.ftl
             +- <other templates>

更多复杂的映射,还可以使用ErrorViewResolver来实现:
public class MyErrorViewResolver implements ErrorViewResolver {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map<String, Object> model) {
// Use the request or status to optionally return a ModelAndView
return ...
}
}
我们也可以通过使用springmvc的特性来处理不同的异常,比如:@ExceptionHandler,@ControllerAdvice。其他没有被处理的异常都会被ErrorController拦截处理

8. CORS support(跨站点资源访问)

在Spring-mvc中已经支持跨站点资源访问,只需要在需要访问的类或方法上面添加注解@CrossOrigin,也可以配置全局的跨站点访问 参考文档
Spring-boot配置全局的跨站点访问:

@Configuration
public class MyConfiguration {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**");
            }
        };
    }
}
l9. Embedded servlet container support(内嵌的servlet容器)

Spring-boot 已经内嵌了Tomcat,Jetty服务器,默认监听的端口是8080

9.1 Registering Servlets, Filters, and listeners

当使用Spring boot的嵌入式servlet容器时,可以通过Spring bean或扫描Servlet组件的方式注册Servlet、Filter和Servlet规范的所有监听器(例如HttpSessionListener)。
当urlMapping不是很复杂时,可以通过ServletRegistrationBean、FilterRegistrationBean 和ServletListenerRegistrat<wbr>ionBean获得完整控制。如果bean实现了ServletContextInitialize<wbr>r接口的话则可以直接注册。

@Configuration
@ComponentScan(basePackages = "com.spring.boot.controller3")
public class WebConfigure extends WebMvcConfigurerAdapter {
    @Bean
    public ServletRegistrationBean getLogServlet(LogServlet logServlet) {
        return new ServletRegistrationBean(logServlet, "/logServlet");
    }
}
@Component
public class LogServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.print("Log Servlet welcome!");
        writer.close();
    }
}

当使用@ServletComponentScan扫描Servlet组件时,Servlet、过滤器和监听器可以是通过@WebServlet、@WebFilter和@WebListener自动注册

@Configuration
@ServletComponentScan(basePackages = "com.spring.boot.component")
public class WebConfigure extends WebMvcConfigurerAdapter {
}
@WebServlet(urlPatterns = {"/logServlet2"})
public class LogServlet2 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.print("Log Servlet2 welcome!");
        writer.close();
    }
}
9.2 Servlet Context Initialization

对于这种内嵌的Servlet容器,在初始化的时候不会去执行javax.servlet.ServletContainerInitializer这个接口,而是执行spring的接口org.springframework.web.WebApplicationInitializer。如果你需要在spring-boot的应用中去处理初始化的工作,可以注册一个Spring Bean实现接口org.springframework.boot.context.embedded.ServletContextInitializer

@Component
public class AppServletContextInitializer implements ServletContextInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        System.out.println("============ AppServletContextInitializer ===============");
    }
}
9.3 Customizing embedded servlet containers(配置嵌入的Servlet容器)
  • 在applicat-ion.properties中配置参数

    server.port : 配置监听的端口
    server.address : 监听地址
    server.session.timeout : session过期时间
    server.session.persistence : 是否需要持久化session
    server.session.store-dir : session存储位置

更多其他配置参考类 ServerProperties

  • 通过编程的方式实现

    import org.springframework.boot.context.embedded.*;
    import org.springframework.stereotype.Component;
    @Component
    public class CustomizationBean implements EmbeddedServletContainerCustomizer {
    @Override
    public void customize(ConfigurableEmbeddedServletContainer container) {
    container.setPort(9000);
    }
    }

实现EmbeddedServletContainerCustomizer接口,编程配置参数

  • 如果以上两种方式你觉得不灵活,你可以使用 TomcatEmbeddedServletContainerFactory,JettyEmbeddedServletContainerFactoryor UndertowEmbeddedServletContainerFactory

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
    TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
    factory.setPort(9000);
    factory.setSessionTimeout(10, TimeUnit.MINUTES);
    factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
    return factory;
    }


Working with SQL databases(使用SQL数据库)

1. 配置数据库连接池
1. Spring-boot能够自动配置数据库连接池DataSource,自动选择的规则:
2. 因为Tomcat的连接池效率和并发性都比较高,所以如果允许,都会选择使用
3. 否则,如果HikariCP允许,就会选择HikariCP
4. 如果Tomcat pooling datasource和HikariCP都不能使用,那么将会选择使用 DBCP
5. 最后,以上3中都不能使用,就会选择使用DBCP2

如果你使用了spring-boot-starter-jdbc, spring-boot-starter-data-jpa ,那么Spring-boot将会自动配置tomcat-jdbc
也可以通过使用spring.datasource.type来手动配置使用哪种,比如:配置阿里巴巴开源项目druid
更多的数据库参数配置,参考类DataSourceProperties

2. Using JdbcTemplate

Spring-boot会自动配置JdbcTemplate,可以直接使用@Autowire来注入使用

@Component
public class MyBean {
    private final JdbcTemplate jdbcTemplate;
    @Autowired
    public MyBean(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    // ...
}
3. JPA and ‘Spring Data’

在Spring-boot应用中,可以使用spring-boot-starter-data-jpa作为一个开始,会包含一下依赖:
Hibernate — One of the most popular JPA implementations.
Spring Data JPA — Makes it easy to implement JPA-based repositories.
Spring ORMs — Core ORM support from the Spring Framework.
3.1 Entity Classes And Spring Data JPA Repositories
默认情况下,Spring-boot会扫描主要配置类(有注解@EnableAutoConfiguration or@SpringBootApplication)下面的所有包,任何被@Entity, @Embeddable or @MappedSuperclass注解的类都会作为实体;任何继承了Repository or CrudRepository的接口都会被作为 Repository,不需要任何@Component or Repository
如果你想要自定义寻找的Entity的存放位置,可以使用注解@EntityScan。

Caching 参考文档

Sending email

Spring框架提供了一个发送邮件的类JavaMailSender。
如果在容器中找不到一个存在的JavaMailSender,配置了参数spring.mail.host并且相关包存在(spring-boot-starter-mail导入相关包),那么就会自动创建一个JavaMailSender。
邮件配置参数都是以spring.mail开头,更多参数配置参考类: MailProperties

#发送邮件配置
spring.mail.host=smtp.sina.cn
spring.mail.username=silentwu@sina.cn
spring.mail.password=asdewq
@RestController
@RequestMapping("/mail")
public class MailController {
    @Autowired
    private JavaMailSender mailSender;
    @RequestMapping("/send")
    public String sendMail() {
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setTo("380303318@qq.com");
        mailMessage.setFrom("silentwu@sina.cn");
        mailMessage.setSubject(" 测试简单文本邮件发送! ");
        mailMessage.setText(" 测试我的简单邮件发送机制!! ");
        mailSender.send(mailMessage);
        return "send mail success...";
    }
}

Spring Session 参考文档


Monitoring and management over JMX 参考文档

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容