springBoot特性整理(基础版)

1、自定义SpringApplication

自定义bannnr

public static void main(String[] args){
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setShowBanner(false);
app.run(args);
}

流畅式API构建

new SpringApplicationBuilder()
.showBanner(false)
.sources(Parent.class)
.child(Application.class)
.run(args);

时间和监听


可以使用多种方式注册事件监听器,最普通的是使用SpringApplication.addListeners(…)方法。在你的应用运行时,应用事
件会以下面的次序发送:
1. 在运行开始,但除了监听器注册和初始化以外的任何处理之前,会发送一个ApplicationStartedEvent。
2. 在Environment将被用于已知的上下文,但在上下文被创建前,会发送一个ApplicationEnvironmentPreparedEvent。
3. 在refresh开始前,但在bean定义已被加载后,会发送一个ApplicationPreparedEvent。
4. 启动过程中如果出现异常,会发送一个ApplicationFailedEvent。

web环境

在默认情况下,使用
AnnotationConfigApplicationContext或AnnotationConfigEmbeddedWebApplicationContext取决于你正在开发的是否是web
应用。
用于确定一个web环境的算法相当简单(基于是否存在某些类)。如果需要覆盖默认行为,你可以使用
setWebEnvironment(boolean webEnvironment)。通过调用setApplicationContextClass(…),你可以完全控制
ApplicationContext的类型。
注:当JUnit测试里使用SpringApplication时,调用setWebEnvironment(false)是可取的。

命令行启动

如果你想获取原始的命令行参数,或一旦SpringApplication启动,你需要运行一些特定的代码,你可以实现
CommandLineRunner接口。在所有实现该接口的Spring beans上将调用run(String… args)方法。

import org.springframework.boot.*
import org.springframework.stereotype.*
@Component
public class MyBean implements CommandLineRunner {
public void run(String... args) {
// Do something...
}
}


如果一些CommandLineRunner beans被定义必须以特定的次序调用,你可以额外实现org.springframework.core.Ordered接
口或使用org.springframework.core.annotation.Order注解。

退出

每个SpringApplication在退出时为了确保ApplicationContext被优雅的关闭,将会注册一个JVM的shutdown钩子。所有标准的
Spring生命周期回调(比如,DisposableBean接口或@PreDestroy注解)都能使用。
此外,如果beans想在应用结束时返回一个特定的退出码(exit code),可以实现
org.springframework.boot.ExitCodeGenerator接口
 

2、外化配置使用


Spring Boot使用一个非常特别的PropertySource次序来允许对值进行合理的覆盖,需要以下面的次序考虑属性:
1. 命令行参数
2. 来自于java:comp/env的JNDI属性
3. Java系统属性(System.getProperties())
4. 操作系统环境变量
5. 只有在random.*里包含的属性会产生一个RandomValuePropertySource
6. 在打包的jar外的应用程序配置文件(application.properties,包含YAML和profile变量)
7. 在打包的jar内的应用程序配置文件(application.properties,包含YAML和profile变量)
8. 在@Configuration类上的@PropertySource注解
9. 默认属性(使用SpringApplication.setDefaultProperties指定

配置随机值

RandomValuePropertySource在注入随机值(比如,密钥或测试用例)时很有用。它能产生整数,longs或字符串,比如:

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}


random.int*语法是OPEN value (,max) CLOSE,此处OPEN,CLOSE可以是任何字符,并且value,max是整数。如果提供
max,那么value是最小的值,max是最大的值(不包含在内)

命令行属性

默认情况下,SpringApplication将任何可选的命令行参数(以'--'开头,比如,--server.port=9000)转化为property,并将其
添加到Spring Environment中。如上所述,命令行属性总是优先于其他属性源。
如果你不想将命令行属性添加到Environment里,你可以使用SpringApplication.setAddCommandLineProperties(false)来禁
止它们。

Application属性文件

SpringApplication将从以下位置加载application.properties文件,并把它们添加到Spring Environment中:
1. 当前目录下的一个/config子目录
2. 当前目录
3. 一个classpath下的/config包
4. classpath根路径(root)
这个列表是按优先级排序的(列表中位置高的将覆盖位置低的)。
注:你可以使用YAML('.yml')文件替代'.properties'。
如果不喜欢将application.properties作为配置文件名,你可以通过指定spring.config.name环境属性来切换其他的名称。你也
可以使用spring.config.location环境属性来引用一个明确的路径(目录位置或文件路径列表以逗号分割)。

$ java -jar myproject.jar --spring.config.name=myproject
//or
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties


如果spring.config.location包含目录(相对于文件),那它们应该以/结尾(在加载前,spring.config.name产生的名称将被追
加到后面)。不管spring.config.location是什么值,默认的搜索路径classpath:,classpath:/config,file:,file:config/总会被使用。
以这种方式,你可以在application.properties中为应用设置默认值,然后在运行的时候使用不同的文件覆盖它,同时保留默认
配置。
注:如果你使用环境变量而不是系统配置,大多数操作系统不允许以句号分割(period-separated)的key名称,但你可以使
用下划线(underscores)代替(比如,使用SPRING_CONFIG_NAME代替spring.config.name)。如果你的应用运行在一
个容器中,那么JNDI属性(java:comp/env)或servlet上下文初始化参数可以用来取代环境变量或系统属性,当然也可以使
用环境变量或系统属性

属性占位符

app.name=MyApp
app.description=${app.name} is a Spring Boot application

属性配置文件加载

Spring框架提供两个便利的类用于加载YAML文档,YamlPropertiesFactoryBean会将YAML作为Properties来加载,
YamlMapFactoryBean会将YAML作为Map来加载,

注意:yaml文件无法像properties文件那样使用@PropertySource 注解加载

特殊用法:

YAML列表被表示成使用[index]间接引用作为属性keys的形式,例如下面的YAML:
my:
servers:
- dev.bar.com
- foo.bar.com
将会转化到下面的属性中:
my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com

类型安全的配置属性

即使用@ConfigurationProperties注解,适合于和外部配置文件结合使用;

@Component
@ConfigurationProperties(prefix="connection")
public class ConnectionSettings {
private String username;
private InetAddress remoteAddress;
// ... getters and setters
}
# application.yml
connection:
username: admin
remoteAddress: 192.168.1.1
# additional configuration as required

使用方式:

@Service
public class MyService {
@Autowired
private ConnectionSettings connection;
//...
@PostConstruct
public void openConnection() {
Server server = new Server();
this.connection.configure(server);
}
}

你可以通过在@EnableConfigurationProperties注解中直接简单的列出属性类来快捷的注册@ConfigurationProperties bean
的定义。
 

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

第三方配置

当你需要绑定属性到不受你控制的第三
方组件时,这种方式非常有用。
为了从Environment属性配置一个bean,将@ConfigurationProperties添加到它的bean注册过程:

@ConfigurationProperties(prefix = "foo")
@Bean
public FooComponent fooComponent() {
...
}


和上面ConnectionSettings的示例方式相同,任何以foo为前缀的属性定义都会被映射到FooComponent上。

松散绑定

Spring Boot使用一些宽松的规则用于绑定Environment属性到@ConfigurationProperties beans,所以Environment属性名和
bean属性名不需要精确匹配。常见的示例中有用的包括虚线分割(比如,context--path绑定到contextPath)和将环境属性转
为大写字母(比如,PORT绑定port)。
示例:

@Component
@ConfigurationProperties(prefix="person")
public class ConnectionSettings {
private String firstName;
}

下面的属性名都能用于上面的@ConfigurationProperties类:
属性
说明
person.firstName
标准驼峰规则
person.first-name
虚线表示,推荐用于.properties和.yml文件中
PERSON_FIRST_NAME
大写形式,使用系统环境变量时推荐

Spring会尝试强制外部的应用属性在绑定到@ConfigurationProperties beans时类型是正确的。如果需要自定义类型转换,你
可以提供一个ConversionService bean(bean id为conversionService)或自定义属性编辑器(通过一个
CustomEditorConfigurer bean)。

@ConfigurationProperties校验

@Component
@ConfigurationProperties(prefix="connection")
public class ConnectionSettings {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}

你也可以通过创建一个叫做configurationPropertiesValidator的bean来添加自定义的Spring Validator。
注:spring-boot-actuator模块包含一个暴露所有@ConfigurationProperties beans的端点。简单地将你的web浏览器指
向/configprops或使用等效的JMX端点。

Profiles

Spring Profiles提供了一种隔离应用程序配置的方式,并让这些配置只能在特定的环境下生效。任何@Component或
@Configuration都能被@Profile标记,从而限制加载它的时机。

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

或使用命令行:--spring.profiles.active=dev,hsqldb

Profiles激活

spring.profiles.active属性和其他属性一样都遵循相同的排列规则,最高的PropertySource获胜。也就是说,你可以在
application.properties中指定生效的配置,然后使用命令行开关替换它们。
有时,将特定的配置属性添加到生效的配置中而不是替换它们是有用的。spring.profiles.include属性可以用来无条件的添加
生效的配置。SpringApplication的入口点也提供了一个用于设置额外配置的Java API(比如,在那些通过
spring.profiles.active属性生效的配置之上):参考setAdditionalProfiles()方法。
示例:当一个应用使用下面的属性,并用 --spring.profiles.active=prod 开关运行,那proddb和prodmq配置也会生效:
---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include: proddb,prodmq
注:spring.profiles属性可以定义到一个YAML文档中,用于决定什么时候该文档被包含进配置中。

你也可以通过调用SpringApplication.setAdditionalProfiles(…)方法,以编程的方式设置生效的配置。使用
Spring的ConfigurableEnvironment接口激动配置也是可行的。

日志

Spring Boot内部日志系统使用的是Commons Logging,但开放底层的日志实现。默认情况下,Spring Boot只会将日志记录到控制台而不会写进日志文件。

通过 --debug 标识开启控制台的DEBUG级别日志记录。

如果你的终端支持ANSI,为了增加可读性将会使用彩色的日志输出。你可以设置 spring.output.ansi.enabled 为一个支持的值来覆盖自动检测

通过将适当的库添加到classpath,可以激活各种日志系统。然后在classpath的根目录(root)或通过Spring Environment
的 logging.config 属性指定的位置提供一个合适的配置文件来达到进一步的定制(注意由于日志是在ApplicationContext被创
建之前初始化的,所以不可能在Spring的@Configuration文件中,通过@PropertySources控制日志。系统属性和平常的
Spring Boot外部配置文件能正常工作)。

3、自动配置

自动配置添加了以下特性:
1. 引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。
2. 对静态资源的支持,包括对WebJars的支持。
3. 自动注册Converter,GenericConverter,Formatter beans。
4. 对HttpMessageConverters的支持。
5. 自动注册MessageCodeResolver。
6. 对静态index.html的支持。
7. 对自定义Favicon的支持。
如果想全面控制Spring MVC,你可以添加自己的@Configuration,并使用@EnableWebMvc对其注解。如果想保留Spring
Boot MVC的特性,并只是添加其他的MVC配置(拦截器,formatters,视图控制器等),你可以添加自己的WebMvcConfigurerAdapter类型的@Bean(不使用@EnableWebMvc注解)。

4、HttpMessageConverter

Spring MVC使用HttpMessageConverter接口转换HTTP请求和响应。合理的缺省值被包含的恰到好处(out of the box),例
如对象可以自动转换为JSON(使用Jackson库)或XML(如果Jackson XML扩展可用则使用它,否则使用JAXB)。字符串
默认使用UTF-8编码。
如果需要添加或自定义转换器,你可以使用Spring Boot的HttpMessageConverters类:

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;
@Configuration
public class MyConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}
}

任何在上下文中出现的HttpMessageConverter bean将会添加到converters列表,你可以通过这种方式覆盖默认的转换器(converters)。

该接口主要方法如下:

boolean canRead(Class<?> clazz, MediaType mediaType);
boolean canWrite(Class<?> clazz, MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;
void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;

源码中数据转化默认如下:

protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
		StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
		stringConverter.setWriteAcceptCharset(false);

		messageConverters.add(new ByteArrayHttpMessageConverter());
		messageConverters.add(stringConverter);
		messageConverters.add(new ResourceHttpMessageConverter());
		messageConverters.add(new SourceHttpMessageConverter<Source>());
		messageConverters.add(new AllEncompassingFormHttpMessageConverter());

		if (romePresent) {
			messageConverters.add(new AtomFeedHttpMessageConverter());
			messageConverters.add(new RssChannelHttpMessageConverter());
		}

		if (jackson2XmlPresent) {
			ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build();
			messageConverters.add(new MappingJackson2XmlHttpMessageConverter(objectMapper));
		}
		else if (jaxb2Present) {
			messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
		}

		if (jackson2Present) {
			ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build();
			messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
		}
		else if (gsonPresent) {
			messageConverters.add(new GsonHttpMessageConverter());
		}
	}

只有在没有定制时才调用默认的方法:

protected final List<HttpMessageConverter<?>> getMessageConverters() {
		if (this.messageConverters == null) {
			this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
			configureMessageConverters(this.messageConverters);
			if (this.messageConverters.isEmpty()) {
				addDefaultHttpMessageConverters(this.messageConverters);
			}
			extendMessageConverters(this.messageConverters);
		}
		return this.messageConverters;
	}

定制化
空值处理
请求和返回的数据有很多空值,这些值有时候并没有实际意义,我们可以过滤掉和不返回,或设置成默认值。比如通过重写 getObjectMapper 方法,将返回结果的空值不进行序列化:

converters.add(0, new MappingJackson2HttpMessageConverter(){
    @Override
    public ObjectMapper getObjectMapper() {
        super.getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
                return super.getObjectMapper();
    }
}


XSS 脚本攻击
为了保证输入的数据更安全,防止 XSS 脚本攻击,我们可以添加自定义反序列化器:

//对应无法直接返回String类型
converters.add(0, new MappingJackson2HttpMessageConverter(){
    @Override
    public ObjectMapper getObjectMapper() {
        super.getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);

                // XSS 脚本过滤
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addDeserializer(String.class, new StringXssDeserializer());
        super.getObjectMapper().registerModule(simpleModule);

        return super.getObjectMapper();
    }

将各种常用 HttpMessageConverter 支持的MediaType 和 JavaType 以及对应关系总结在此处:

类名    支持的JavaType    支持的MediaType
ByteArrayHttpMessageConverter    byte[]    application/octet-stream, */*
StringHttpMessageConverter    String    text/plain, */*
MappingJackson2HttpMessageConverter    Object    application/json, application/*+json
AllEncompassingFormHttpMessageConverter    Map<K, List<?>>    application/x-www-form-urlencoded, multipart/form-data
SourceHttpMessageConverter    Source    application/xml, text/xml, application/*+xml
 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值