原创作者:田超凡(程序员田宝宝)
版权所有,引用请注明原作者,严禁复制转载
整合配置文件
1.在springboot整合配置文件,分成两大类:
application.properties
application.yml
或者是
Bootstrap.properties
Bootstrap.yml
相对于来说yml文件格式写法更加精简,减少配置文件的冗余性。
2.加载顺序:
bootstrap.yml 先加载 application.yml后加载
bootstrap.yml 用于应用程序上下文的引导阶段。
bootstrap.yml 由父Spring ApplicationContext加载。
- 区别:
bootstrap.yml 和 application.yml 都可以用来配置参数。
bootstrap.yml 用来程序引导时执行,应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。一旦bootStrap.yml 被加载,则内容不会被覆盖。
application.yml 可以用来定义应用级别, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
分布式配置中心:
Properties在线转换yml格式网址:https://www.toyaml.com/index.html
7.1使用@value注解:
@Value("${tcf.name}")private String name; |
7.2@ConfigurationProperties
<!--导入配置文件处理器,配置文件进行绑定就会有提示--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency> import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;
@Component@ConfigurationProperties(prefix = "tcf")public class TcfUserEntity {private String addres;private String age;private String name;public String getAddres() {return addres;}public String getAge() {return age;}public String getName() {return name;}public void setAddres(String addres) {this.addres = addres;}public void setAge(String age) {this.age = age;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "TcfUserEntity{" +"addres='" + addres + '\'' +", age='" + age + '\'' +", name='" + name + '\'' +'}';}} tcf:addres: www.tcf.comage: 22name: tcf @Autowiredprivate TcfUserEntity tcfUserEntity; @RequestMapping("/getNameAndAgeAddres")public String getNameAndAgeAddres() {return tcfUserEntity.toString();} |
7.3配置文件占位符
在SpringBoot的配置文件中,我们可以使用SpringBoot提供的的一些随机数
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
-${app.name:默认值} 来制定找不到属性时的默认值
7.4多环境配置
spring:profiles:active: pre |
application-dev.yml:开发环境 application-test.yml:测试环境 application-prd.yml:生产环境 |
7.5、核心配置
server:port: 8081servlet:context-path: /tcf
Springboot 默认的情况下整合tomcat容器
- 日志管理
8.1.使用logback记录日志
Springboot 已经默认帮你整合好了logback
日志输出文件在当前项目路径log文件夹下
Maven依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency> |
Logback配置
<configuration><!--本文主要输出日志为控制台日志,系统日志,sql日志,异常日志--><!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,,,, --><!--控制台--><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d %p (%file:%line\)- %m%n</pattern><charset>UTF-8</charset></encoder></appender><!--系统info级别日志--><!--<File> 日志目录,没有会自动创建--><!--<rollingPolicy>日志策略,每天建立一个日志文件,或者当天日志文件超过64MB时--><!--encoder 日志编码及输出格式--><appender name="fileLog"class="ch.qos.logback.core.rolling.RollingFileAppender"><File>log/file/fileLog.log</File><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>log/file/fileLog.log.%d.%i</fileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><!-- or whenever the file size reaches 64 MB --><maxFileSize>64 MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder><pattern>
%d %p (%file:%line\)- %m%n</pattern><charset>UTF-8</charset><!-- 此处设置字符集 --></encoder></appender><!--sql日志--><appender name="sqlFile"class="ch.qos.logback.core.rolling.RollingFileAppender"><File>log/sql/sqlFile.log</File><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>log/sql/sqlFile.log.%d.%i</fileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><!-- or whenever the file size reaches 64 MB --><maxFileSize>64 MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!--对记录事件进行格式化。负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。--><encoder><!--用来设置日志的输入格式--><pattern>
%d %p (%file:%line\)- %m%n</pattern><charset>UTF-8</charset><!-- 此处设置字符集 --></encoder></appender><!--异常日志--><appender name="errorFile"class="ch.qos.logback.core.rolling.RollingFileAppender"><File>log/error/errorFile.log</File><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>log/error/errorFile.%d.log.%i</fileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><!-- or whenever the file size reaches 64 MB --><maxFileSize>64 MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!--对记录事件进行格式化。负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。--><encoder><!--用来设置日志的输入格式--><pattern>
%d %p (%file:%line\)- %m%n</pattern><charset>UTF-8</charset><!-- 此处设置字符集 --></encoder><!--日志都在这里 过滤出 error使用 try {}catch (Exception e){} 的话异常无法写入日志,可以在catch里用logger.error()方法手动写入日志--><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender><!-- 日志输出级别 --><!--All\DEBUG\INFO\WARN\ERROR\FATAL\OFF--><!--打印info级别日志,分别在控制台,fileLog,errorFile输出异常日志在上面由过滤器过滤出ERROR日志打印--><root level="INFO"><appender-ref ref="fileLog" /><appender-ref ref="console" /><appender-ref ref="errorFile" /></root><!--打印sql至sqlFile文件日志--><logger name="com.dolphin.mapper" level="DEBUG" additivity="false"><appender-ref ref="console" /><appender-ref ref="sqlFile" /></logger></configuration> |
application
###指定读取logback配置文件logging:config: classpath:log/logback.xml |
测试案例
@RestController@Slf4jpublic class MyIndexService { @RequestMapping("/getName")public String getName(String name, int age) {log.info("name:{},age:{}", name, age);return name;} } |
日志级别
ALL 最低等级的,用于打开所有日志记录。
TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志级别,一般不会使用。
DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。
WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示
ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
OFF 最高等级的,用于关闭所有日志记录。
日志目录
8.2.使用log4j记录日志
日志级别
机制:如果一条日志信息的级别大于等于配置文件的级别,就记录。
trace:追踪,就是程序推进一下,可以写个trace输出
debug:调试,一般作为最低级别,trace基本不用。
info:输出重要的信息,使用较多
warn:警告,有些信息不是错误信息,但也要给程序员一些提示。
error:错误信息。用的也很多。
fatal:致命错误。
输出源
CONSOLE(输出到控制台)
FILE(输出到文件)
格式
SimpleLayout:以简单的形式显示
HTMLLayout:以HTML表格显示
PatternLayout:自定义形式显示
8.2.1新建log4j配置文件
文件名称log4j.properties
#log4j.rootLogger=CONSOLE,info,error,DEBUGlog4j.rootLogger=DEBUG,error,CONSOLE,infolog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.logger.info=infolog4j.appender.info=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.info.layout=org.apache.log4j.PatternLayout log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.appender.info.datePattern='.'yyyy-MM-ddlog4j.appender.info.Threshold = info log4j.appender.info.append=truelog4j.appender.info.File=E:/code/log/info.loglog4j.logger.error=error log4j.appender.error=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.error.layout=org.apache.log4j.PatternLayout log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.appender.error.datePattern='.'yyyy-MM-ddlog4j.appender.error.Threshold = error log4j.appender.error.append=truelog4j.appender.error.File=E:/code/log/error.loglog4j.logger.DEBUG=DEBUGlog4j.appender.DEBUG=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.DEBUG.layout=org.apache.log4j.PatternLayout log4j.appender.DEBUG.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n log4j.appender.DEBUG.datePattern='.'yyyy-MM-ddlog4j.appender.DEBUG.Threshold = DEBUG log4j.appender.DEBUG.append=truelog4j.appender.DEBUG.File=E:/code/log/dubug.log log4j代码 private static final Logger logger = LoggerFactory.getLogger(IndexController.class); |
8.2.2.Maven依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- spring boot start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><!-- 排除自带的logback依赖 --><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><!-- springboot-log4j --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j</artifactId><version>1.3.8.RELEASE</version></dependency> |
8.2.3.application
###指定log4j.properties配置文件路径logging:config: classpath:log4j.properties |
8.3.使用AOP统一处理Web请求日志
基于AOP实现 或者elk
在我们的方法的前后实现拦截 减少打印日志代码的冗余性的问题
8.3.1 POM文件新增依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> |
6.3.2 AOP切面相关配置
@Aspect @Component public class WebLogAspect { private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class); @Pointcut("execution(public * com.tcf.controller.*.*(..))") public void webLog() { } @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 记录下请求内容 logger.info("URL : " + request.getRequestURL().toString()); logger.info("HTTP_METHOD : " + request.getMethod()); logger.info("IP : " + request.getRemoteAddr()); Enumeration<String> enu = request.getParameterNames(); while (enu.hasMoreElements()) { String name = (String) enu.nextElement(); logger.info("name:{},value:{}", name, request.getParameter(name)); } } @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) throws Throwable { // 处理完请求,返回内容 logger.info("RESPONSE : " + ret); } } |
- 其他内容
9.1、使用@Scheduled创建定时任务
在Spring Boot的主类中加入@EnableScheduling注解,启用定时任务的配置
@Component
public class ScheduledTasks {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedRate = 5000)
public void reportCurrentTime() {
System.out.println("现在时间:" + dateFormat.format(new Date()));
}
}
@Scheduled(cron = "0/2 * * * * *") 写法:
quartz/Cron/Crontab表达式在线生成工具-BeJSON.com
Xxl-job
9.2、使用@Async实现异步调用
启动加上@EnableAsync ,需要执行异步方法上加入 @Async
异步应用场景
@Async实际就是多线程封装的
异步线程执行方法有可能会非常消耗cpu的资源,所以大的项目建议使用
Mq异步实现。
整合线程池
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.task.TaskExecutor;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;@Configuration@EnableAsyncpublic class ThreadPoolConfig {/*** 每秒需要多少个线程处理?* tasks/(1/taskcost)*/private int corePoolSize = 3;/*** 线程池维护线程的最大数量* (max(tasks)- queueCapacity)/(1/taskcost)*/private int maxPoolSize = 3;/*** 缓存队列* (coreSizePool/taskcost)*responsetime*/private int queueCapacity = 10;/*** 允许的空闲时间* 默认为60*/private int keepAlive = 100;@Beanpublic TaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize(corePoolSize);// 设置最大线程数executor.setMaxPoolSize(maxPoolSize);// 设置队列容量executor.setQueueCapacity(queueCapacity);// 设置允许的空闲时间(秒)//executor.setKeepAliveSeconds(keepAlive);// 设置默认线程名称executor.setThreadNamePrefix("thread-");// 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);return executor;}} import lombok.extern.slf4j.Slf4j;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Component;
@Slf4j@Componentpublic class MemberServiceAsync {@Async("taskExecutor")public String smsAsync() {log.info(">02<");try {log.info(">正在发送短信..<");Thread.sleep(3000);} catch (Exception e) {}log.info(">03<");return "短信发送完成!";}} |
异步注解配置类
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.task.TaskExecutor;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;@Configuration@EnableAsyncpublic class ThreadPoolConfig {/*** 每秒需要多少个线程处理?* tasks/(1/taskcost)*/private int corePoolSize = 3;/*** 线程池维护线程的最大数量* (max(tasks)- queueCapacity)/(1/taskcost)*/private int maxPoolSize = 3;/*** 缓存队列* (coreSizePool/taskcost)*responsetime*/private int queueCapacity = 10;/*** 允许的空闲时间* 默认为60*/private int keepAlive = 100;@Beanpublic TaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize(corePoolSize);// 设置最大线程数executor.setMaxPoolSize(maxPoolSize);// 设置队列容量executor.setQueueCapacity(queueCapacity);// 设置允许的空闲时间(秒)//executor.setKeepAliveSeconds(keepAlive);// 设置默认线程名称executor.setThreadNamePrefix("thread-");// 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);return executor;}} |
注意失效问题
注意:如果异步注解写当前自己类,有可能aop会失效,无法拦截注解,最终导致异步注解失效,需要经过代理类调用接口;
所以需要将异步的代码单独抽取成一个类调用接口。
9.3全局捕获异常
@ExceptionHandler 表示拦截异常
- @ControllerAdvice 是 controller 的一个辅助类,最常用的就是作为全局异常处理的切面类
- @ControllerAdvice 可以指定扫描范围
- @ControllerAdvice 约定了几种可行的返回值,如果是直接返回 model 类的话,需要使用 @ResponseBody 进行 json 转换
- 返回 String,表示跳到某个 view
- 返回 modelAndView
- 返回 model + @ResponseBody
@ControllerAdvicepublic class TcfExceptionHandler {/*** 拦截运行异常出现的错误~~~** @return*/@ExceptionHandler(RuntimeException.class)@ResponseBodypublic Map<Object, Object> exceptionHandler() {Map<Object, Object> map = new HashMap<>();map.put("error", "500");map.put("msg", "系统出现错误~");return map;}} |
9.4发布打包
使用mvn package 打包
使用java –jar 包名
如果报错没有主清单,在pom文件中新增
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><goals><goal>repackage</goal></goals></execution></executions><configuration><mainClass>com.tcf.App</mainClass><excludes><exclude><groupId>junit</groupId><artifactId>junit</artifactId></exclude><exclude><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></exclude></excludes></configuration></plugin></plugins></build> |
本文部分素材转载自蚂蚁课堂