SpringBoot常用配置類大全
【结合源码看注解】
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
SpringBootConfiguration:标注springboot 配置类
SpringBootConfiguration:标注springboot 配置类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
底层是Configuration: spring 标注配置类的 一开始是做配置文件,有些配置文件就写成配置类 通过改注解告诉程序这个一个配置类,而Configruation
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@EnableAutoConfiguration 开启自动配置包注解
@AutoConfigurationPackage下的注解 也有import
@AutoConfigurationPackage下的注解 也有import
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
导入的组件由Registrar.class
这个Import真正意义是去扫描springboot中 SpringbootApplication标注的类 下的所以组件到spring容器中
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
真正意义是去扫描springboot中 SpringbootApplication标注的类 下的所以组件到spring容器中
所以编写springboot项目的时候,SpingbootApplication 标注的类一定在所有包,类之外
@import
@Import({AutoConfigurationImportSelector.class})
这给imoprt 是说明要导入那些组件
//将需要导入的组件以全类名返回,就会添加到容器
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
这给String所返回的数据就是 给spring容器导入的xxxAutoConfiguration 自动配置类
给容器中这个场景所需要的所有组件,并配置号这些组件,有了这些配置,就不用手动比那些配置和组件
getCandidateConfigurations 中
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
第一给参数:EnableAutoConfiguration.class; 开启的配置类
第二个参数:ClassLoader; 类加载器 获取到资源 把资源作为一个proertise
SpringBoot在启动时候从类路径下META-INFO/spring.factorise中获取EnableConfigration 指定的值,将这些值自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置,以前需要自动配置的类,自动配置都做了
springboot 都帮我们整合了:javaee自动整合和配置都在 spring-boot-aotoConfigure:...Release
Spring Boot属性配置文件详解
相信很多人选择Spring Boot主要是考虑到它既能兼顾Spring的强大功能,还能实现快速开发的便捷。我们在Spring Boot使用过程中,最直观的感受就是没有了原来自己整合Spring应用时繁多的XML配置内容,替代它的是在pom.xml
中引入模块化的Starter POMs
,其中各个模块都有自己的默认配置,所以如果不是特殊应用场景,就只需要在application.properties
中完成一些属性配置就能开启各模块的应用。
在之前的各篇文章中都有提及关于application.properties
的使用,主要用来配置数据库连接、日志相关配置等。除了这些配置内容之外,本文将具体介绍一些在application.properties
配置中的其他特性和使用方法。
自定义属性与加载
我们在使用Spring Boot的时候,通常也需要定义一些自己使用的属性,我们可以如下方式直接定义:
com.didispace.blog.name=程序猿DDcom.didispace.blog.title=Spring Boot教程
然后通过@Value("${属性名}")
注解来加载对应的配置属性,具体如下:
@Componentpublic class BlogProperties { @Value("${com.didispace.blog.name}") private String name; @Value("${com.didispace.blog.title}") private String title; // 省略getter和setter}
按照惯例,通过单元测试来验证BlogProperties中的属性是否已经根据配置文件加载了。
@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(Application.class)public class ApplicationTests { @Autowired private BlogProperties blogProperties; @Test public void getHello() throws Exception { Assert.assertEquals(blogProperties.getName(), "程序猿DD"); Assert.assertEquals(blogProperties.getTitle(), "Spring Boot教程"); }}
参数间的引用
在application.properties
中的各个参数之间也可以直接引用来使用,就像下面的设置:
com.didispace.blog.name=程序猿DDcom.didispace.blog.title=Spring Boot教程com.didispace.blog.desc=${com.didispace.blog.name}正在努力写《${com.didispace.blog.title}》
com.didispace.blog.desc
参数引用了上文中定义的name
和title
属性,最后该属性的值就是程序猿DD正在努力写《Spring Boot教程》
。
使用随机数
在一些情况下,有些参数我们需要希望它不是一个固定的值,比如密钥、服务端口等。Spring Boot的属性配置文件中可以通过${random}
来产生int值、long值或者string字符串,来支持属性的随机值。
# 随机字符串com.didispace.blog.value=${random.value}# 随机intcom.didispace.blog.number=${random.int}# 随机longcom.didispace.blog.bignumber=${random.long}# 10以内的随机数com.didispace.blog.test1=${random.int(10)}# 10-20的随机数com.didispace.blog.test2=${random.int[10,20]}
通过命令行设置属性值
相信使用过一段时间Spring Boot的用户,一定知道这条命令:java -jar xxx.jar --server.port=8888
,通过使用–server.port属性来设置xxx.jar应用的端口为8888。
在命令行运行时,连续的两个减号--
就是对application.properties
中的属性值进行赋值的标识。所以,java -jar xxx.jar --server.port=8888
命令,等价于我们在application.properties
中添加属性server.port=8888
,该设置在样例工程中可见,读者可通过删除该值或使用命令行来设置该值来验证。
通过命令行来修改属性值固然提供了不错的便利性,但是通过命令行就能更改应用运行的参数,那岂不是很不安全?是的,所以Spring Boot也贴心的提供了屏蔽命令行访问属性的设置,只需要这句设置就能屏蔽:SpringApplication.setAddCommandLineProperties(false)
。
多环境配置
我们在开发Spring Boot应用时,通常同一套程序会被应用和安装到几个不同的环境,比如:开发、测试、生产等。其中每个环境的数据库地址、服务器端口等等配置都会不同,如果在为不同环境打包时都要频繁修改配置文件的话,那必将是个非常繁琐且容易发生错误的事。
对于多环境的配置,各种项目构建工具或是框架的基本思路是一致的,通过配置多份不同环境的配置文件,再通过打包命令指定需要打包的内容之后进行区分打包,Spring Boot也不例外,或者说更加简单。
在Spring Boot中多环境配置文件名需要满足application-{profile}.properties
的格式,其中{profile}
对应你的环境标识,比如:
application-dev.properties
:开发环境application-test.properties
:测试环境application-prod.properties
:生产环境
至于哪个具体的配置文件会被加载,需要在application.properties
文件中通过spring.profiles.active
属性来设置,其值对应{profile}
值。
如:spring.profiles.active=test
就会加载application-test.properties
配置文件内容
下面,以不同环境配置不同的服务端口为例,进行样例实验。
- 针对各环境新建不同的配置文件
application-dev.properties
、application-test.properties
、application-prod.properties
- 在这三个文件均都设置不同的
server.port
属性,如:dev环境设置为1111,test环境设置为2222,prod环境设置为3333 - application.properties中设置
spring.profiles.active=dev
,就是说默认以dev环境设置 - 测试不同配置的加载
- 执行
java -jar xxx.jar
,可以观察到服务端口被设置为1111
,也就是默认的开发环境(dev) - 执行
java -jar xxx.jar --spring.profiles.active=test
,可以观察到服务端口被设置为2222
,也就是测试环境的配置(test) - 执行
java -jar xxx.jar --spring.profiles.active=prod
,可以观察到服务端口被设置为3333
,也就是生产环境的配置(prod)
- 执行
按照上面的实验,可以如下总结多环境的配置思路:
application.properties
中配置通用内容,并设置spring.profiles.active=dev
,以开发环境为默认配置application-{profile}.properties
中配置各个环境不同的内容- 通过命令行方式去激活不同环境的配置
springBoot 中自定義全局异常
@ControllerAdvice
public class GlobalException {
/**
* TODO 可以升华
* 自定义全局异常
*
* @param ex
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public ServerResponse globalHandle(Exception ex) {
StringBuffer stringBuffer = new StringBuffer();
/*MyGlobalException 为自定义异常 */
if (ex instanceof MyGlobalException) {
return ServerResponse.createByError(ex.getMessage());
}
//BindException 为检验的异常
if (ex instanceof BindException) {
BindException bindException = (BindException) ex;
List<ObjectError> allErrors = bindException.getAllErrors();
for (ObjectError error : allErrors) {
String defaultMessage = error.getDefaultMessage();
stringBuffer.append(error.getDefaultMessage());
}
return ServerResponse.createByError(stringBuffer.toString());
}
return ServerResponse.createByError(ex.getMessage());
}
}
自定义异常
继承 Excetion 类 实现自己的异常
public class MyGlobalException extends Exception {
public MyGlobalException(String message) {
super(message);
}
}
拦截器的配置类
通過继承 HandlerInterceptor 实现其下的三个方法
public class UrlInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(UrlInterceptor.class);
private static final String GET_ALL = "/gg";
private static final String GET_HEADER = "/userjsonview";
/**
* 进入Controller层之前拦截请求,默认是拦截所有请求
*
* @param request
* @param response
* @param handler
* @return 是否拦截当前请求,true表示拦截当前请求,false表示不拦截当前请求
* @throws Exception 可能出现的异常
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("go into preHandle.....");
String requestURI = request.getRequestURI();
logger.info(requestURI);
if (requestURI.contains(GET_ALL)) {
throw new MyGlobalException("没有权限");
}
if (requestURI.contains(GET_HEADER)) {
response.sendRedirect("/login");
return true;
}
return true;
}
/**
* 处理完请求后但还未渲染试图之前进行的操作
*
* @param request
* @param response
* @param handler
* @param modelAndView mv
* @throws Exception E
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.info("go into postHandle ...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.info("go into afterCompletion ...");
logger.info("ex: " + ex);
}
实现WebMvcConfigurer接口 在addInterceptors方法中
实现WebMvcConfigurer接口 的addInterceptors方法
@Configuration
//标注为sringboot的配置类
public class MvcConfig implements WebMvcConfigurer {
/*UrlInterceptor
将它注入到Sprig容器,交给spring管理
* */
/* @Bean
public UrlInterceptor urlInterceptor() {
return new UrlInterceptor();
}*/
/*将UrlInterceptor注册到
addInterceptor
* */
@Override
public void addInterceptors(InterceptorRegistry registry) {
/*
addPathPatterns() 需要拦截的路径
excludePathPatterns 不需要拦截的路径
addInterceptor 返回的是InterceptorRegistration对象
*/
registry.addInterceptor(new UrlInterceptor()).addPathPatterns("/**");
}
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
/* 跨域设置‘
* addMapping 跨域的映射地址
* allowedOrigins : 允许跨域的请求源
* allowedMethods: 允许跨域的方法
* allowedHeaders :允许跨域的头部
* allowCredentials : 设置允许cookie session...数据跨域
* */
registry.addMapping("/localhost:8080")
.allowedMethods("/user/**")
.allowedOrigins("/")
.allowedHeaders("token")
.allowCredentials(true);
}
Swagger 接口文档 的配置
在pom中导入依赖
<!--swagger 文档接口支持-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.0</version>
</dependency>
具体配置
@Configuration
@EnableSwagger2
public class SwaggerConfig {
/**
* 链式编程 来定制API样式 后续会加上分组信息
*/
@Bean
public Docket createSwagger() {
HashSet<String> hashSet = new HashSet<>();
hashSet.add("ContentType:Application");
//文档类型
return new Docket(DocumentationType.SWAGGER_2)
//自定义展示的信息)
.apiInfo(MyApiInfo())
// 启动api选择的生成器
.select().
//扫描com路径下的api文档
.apis(RequestHandlerSelectors.basePackage("com"))
.build();
}
// 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
private ApiInfo MyApiInfo() {
return new ApiInfoBuilder()
//设置标题
.title("swagger 测试文档 ")
//接口描述
.description("springboot Rest风格 接口测试")
//设置开发人员一些信息
.contact(new Contact("作者:hzy", "http//8080", "联系: 1372265573@qq.com"))
//设置版本
.version("1.1").build();
}
}
常用注解和
@Api(tags("改接口描述")) 标注 该类是swagger 文档接口 类
@ApiImplicitParams 加 ·s· 可以在里面的花括号写多个 @ApiImplicitParam 用逗号分隔
@ApiModel 标注实体类 在swagger中的那个实体
......... 具体自己去看看
------------------------------------
@Controller
@Api(tags = "Usr 接口 ------")
public class indexController {
// @RequestMapping(value = "/login",method = RequestMethod.GET)
@PostMapping("/login")
@ResponseBody
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用戶名稱", dataType = "String"),
@ApiImplicitParam(name = "password", value = "密碼", dataType = "String")
})
public Map<String, String> login(String username, String password) {
Map<String, String> loginMap = new HashMap<>();
loginMap.put("用户名", username);
loginMap.put("密码", password);
loginMap.put("code", "200");
loginMap.put("STATUS", "登录成功");
return loginMap;
}
springboot yml 基本配置
#服務其配置
server:
port: 9000
#servlet:
# context-path: /book
#数据库相关配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/spring_bookssys?characterEncoding=utf8&&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT&useSSL=false
# 数据源配置
druid:
# druid连接池监控
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: admin
# 初始化时建立物理连接的个数
initial-size: 5
# 最大连接池数量
max-active: 30
# 最小连接池数量
min-idle: 5
# 获取连接时最大等待时间,单位毫秒
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
# 连接保持空闲而不被驱逐的最小时间
min-evictable-idle-time-millis: 300000
# 用来检测连接是否有效的sql,要求是一个查询语句
validation-query: select count(*) from dual
# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
test-while-idle: true
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
test-on-borrow: false
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
test-on-return: false
# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
pool-prepared-statements: false
# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
max-pool-prepared-statement-per-connection-size: 50
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计
filters: stat,wall
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connection-properties:
druid.stat.mergeSql: true
druid.stat.slowSqlMillis: 500
# 合并多个DruidDataSource的监控数据
use-global-data-source-stat: true
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
#解析resources /静态资源
mvc:
static-path-pattern: /**
#mybatis -plus 配置
#xml 扫描,多个目录用逗号或者分隔号(告Mapper所对应的xml 文件位置)
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
auto-mapping-behavior: full
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:mapper/**/*Mapper.xml
configuration:
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
call-setters-on-nulls: true
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
debug: true
pom有关
<!--阿里的数据库连接池支持-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
检验Validation 对实体类的一些字段做检验
pom中依赖的导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
使用測試:
// 所有都验证
@NotNull(message = "不能为空")
private Integer id;
// First 才验证
@NotBlank(message = "字符串类型不能为空字符串(去除后面的空格后)")
@NotNull(message = "对象不能为NULL", groups = {First.class})
@Size(message = "字符串长度为[5-16]", min = 5, max = 16, groups = {Second.class})
@Pattern(regexp = "[a-zA-z]*",message = "正则校验")
private String username;
// First 或 Second 才验证
@NotBlank(message = "字符串类型不能为空字符串(去除后面的空格后)")
@NotNull(message = "对象不能为NULL", groups = {First.class, Second.class})
private String password;
@NotNull(message = "对象不能为NULL", groups = {First.class})
private Integer age;
@NotEmpty(message = "字符串数组集合等不能为空,长度不能为零")
@NotBlank(message = "字符串类型不能为空字符串(去除空格后)")
@NotNull(message = "用户名不能为空")
在控制层使用注解 @Validated 来标注
@PostMapping("/validated")
public Teacher validated(@RequestBody @Validated Teacher teacher) {
return teacher;
}
Spring Aop切面
pom的导入
<!--spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
測試: 首先@Aspect 标注从哪儿去切 定义切面
@Aspect
@Component
//切面
public class AspectTest {
//切点
@Pointcut("execution(* spring.springboot.aspect.AspectTestConfig.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before() {
System.out.println("before : 前");
}
@After("pointcut()")
public void after() {
System.out.println("after : 后");
}
@AfterReturning("pointcut()")
public void afterReturning() {
System.out.println("afterReturning : 在最后一句代码结束的时候");
}
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("afterThrowing : 有异常出现的时候");
}
@Around("pointcut()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前");
proceedingJoinPoint.proceed();
System.out.println("环绕后");
}
}
和上面定义的异常来测试用
@Component
public class AspectTestConfig {
public String aspectTest() throws MyGlobalException {
System.out.println("A Is Aspect-----");
String t = null;
if (t == null) {
throw new MyGlobalException("aop测试异常");
}
return "return 值";
}
}
定义控制层controller来测试
@RestController
@Api(tags = "aspect 切面测试")
public class AspectController {
@Autowired
AspectTestConfig aspectTestConfig;
@ApiImplicitParam(value = "ONLY TEST ", name = "AOP----的切面测试------")
@GetMapping("/aspect")
public String aspectController() throws MyGlobalException {
return aspectTestConfig.aspectTest();
}
}