SpringBoot 知识
基础
脑图
Tomcat启动顺序
先扫包加载类 再启动tomcat容器
Spring 最常用的 7 大类注解整理
@Transactional(rollbackFor = Exception.class)属性详解
Spring中的@Transactional(rollbackFor = Exception.class)属性详解
Spring事务管理(详解+实例)
spring的RestTemplate
配置文件存放位置及读取顺序
@Qualifier注解
@RequestParam @PathVariable @RequestBody注解
@RequestParam
@PathVariable
@RequestBody
Spring Aop实例@Aspect、@Before、@AfterReturning@Around 注解方式配置
Spring Aop实例@Aspect、@Before、@AfterReturning@Around 注解方式配置
@Async@EnableAsync
https://www.cnblogs.com/hsug/p/13303018.html @EnableAsync @Async
https://www.cnblogs.com/uniqueDong/p/10944632.html
https://my.oschina.net/u/4325212/blog/3908133
https://www.jianshu.com/p/fdb4ba80734e
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步线程池
*/
@Configuration
@EnableAsync
public class AsyncExecutorConfig {
/**
* Set the ThreadPoolExecutor's core pool size.
*/
private int corePoolSize = 2;
/**
* Set the ThreadPoolExecutor's maximum pool size.
*/
private int maxPoolSize = 2;
/**
* Set the capacity for the ThreadPoolExecutor's BlockingQueue.
*/
private int queueCapacity = 200;
private String threadNamePrefix = "AsyncExecutor-";
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix(threadNamePrefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import java.util.Random;
import java.util.concurrent.Future;
@Component
@Slf4j
public class AsyncTask {
public static Random random = new Random();
@Async("taskExecutor")
public void sendSms() throws InterruptedException {
log.info("开始做任务3:发送短信");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("完成任务3,耗时:" + (end - start) + "毫秒");
}
// 返回结果的异步调用
@Async("taskExecutor")
public Future<String> pay() throws InterruptedException {
log.info("开始做异步返回结果任务2:支付");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("完成任务2,耗时:" + (end - start) + "毫秒");
return new AsyncResult<>("支付任务2完成");
}
/**
* 会员积分任务
* @throws InterruptedException
*/
@Async("taskExecutor")
public void vip() throws InterruptedException {
log.info("开始做任务5:会员");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("异步返回结果任务5完成,耗时:" + (end - start) + "毫秒");
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Slf4j
@Service
public class OrderService {
public static Random random = new Random();
@Autowired
private AsyncTask asyncTask;
public void doShop() {
try {
createOrder();
// 调用有结果返回的异步任务
Future<String> pay = asyncTask.pay();
Thread.sleep(10000);
if (pay.isDone()) {
try {
String result = pay.get();
log.info("异步任务2返回结果: {}", result);
} catch (ExecutionException e) {
e.printStackTrace();
}
asyncTask.vip();
asyncTask.sendSms();
}
otherJob();
} catch (InterruptedException e) {
log.error("异常", e);
}
log.info("test done");
}
public void createOrder() {
log.info("开始做任务1:下单成功");
}
/**
* 错误使用,不会异步执行:调用方与被调方不能在同一个类。主要是使用了动态代理,同一个类的时候直接调用,不是通过生成的动态代理类调用
*/
@Async("taskExecutor")
public void otherJob() {
log.info("开始做任务4:物流");
long start = System.currentTimeMillis();
try {
Thread.sleep(random.nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
log.info("完成任务4,耗时:" + (end - start) + "毫秒");
}
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AsyncApplication.class)
public class AsyncApplicationTests {
@Autowired
private OrderService orderService;
@Test
public void testAsync() {
orderService.doShop();
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2020-12-22 11:27:22.858 INFO 15568 --- [ main] com.lx.async.OrderService : 开始做任务1:下单成功
2020-12-22 11:27:22.874 INFO 15568 --- [AsyncExecutor-1] com.lx.async.AsyncTask : 开始做异步返回结果任务2:支付
2020-12-22 11:27:32.646 INFO 15568 --- [AsyncExecutor-1] com.lx.async.AsyncTask : 完成任务2,耗时:9772毫秒
2020-12-22 11:27:32.867 INFO 15568 --- [ main] com.lx.async.OrderService : 异步任务2返回结果: 支付任务2完成
2020-12-22 11:27:32.875 INFO 15568 --- [ main] com.lx.async.OrderService : 开始做任务4:物流
2020-12-22 11:27:32.875 INFO 15568 --- [AsyncExecutor-1] com.lx.async.AsyncTask : 开始做任务3:发送短信
2020-12-22 11:27:32.875 INFO 15568 --- [AsyncExecutor-2] com.lx.async.AsyncTask : 开始做任务5:会员
2020-12-22 11:27:38.135 INFO 15568 --- [AsyncExecutor-2] com.lx.async.AsyncTask : 异步返回结果任务5完成,耗时:5259毫秒
2020-12-22 11:27:39.895 INFO 15568 --- [AsyncExecutor-1] com.lx.async.AsyncTask : 完成任务3,耗时:7019毫秒
2020-12-22 11:27:40.204 INFO 15568 --- [ main] com.lx.async.OrderService : 完成任务4,耗时:7328毫秒
2020-12-22 11:27:40.204 INFO 15568 --- [ main] com.lx.async.OrderService : test done
logback日志
进阶
降级-熔断-限流
降级 干掉一些次要功能
熔断原理
保险丝 熔断器模式最牛的是能让应用程序自我诊断下游系统的错误是否已经修正,如果没有,不放量去请求,如果请求成功了,慢慢的增加请求,再次尝试调用。阿里的Sentinel
限流的实现方式
①计数器
最简单的实现方式 ,维护一个计数器,来一个请求计数加一,达到阈值时,直接拒绝请求。
一般实践中用 ngnix + lua + redis 这种方式,redis 存计数值
②漏斗模式
流量就像进入漏斗中的水一样,而出去的水和我们系统处理的请求一样,当流量大于漏斗的流出速度,就会出现积水,水对了会溢出。
漏斗很多是用一个队列实现的,当流量过多时,队列会出现积压,队列满了,则开始拒绝请求。
③令牌桶
令牌通和漏斗模式很像,主要的区别是增加了一个中间人,这个中间人按照一定的速率放入一些token,然后,处理请求时,需要先拿到token才能处理,如果桶里没有token可以获取,则不进行处理。