线程池和切面
-
配置线程池
在springboot中开启线程池:
- 配置线程池
- 在需要的方法上添加注解@Async
/** * @ClassName ExecutorConfig * @date 2021/7/15 9:52 * @Description 线程池配置 * @Author bXiua * @Version 1.0 */ @Configuration @EnableAsync public class ExecutorConfig { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Bean public Executor asyncServiceExecutor() { logger.info("start asyncServiceExecutor"); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //配置核心线程数 executor.setCorePoolSize(5); //配置最大线程数 executor.setMaxPoolSize(5); //配置队列大小 executor.setQueueCapacity(99999); //配置线程池中的线程的名称前缀 executor.setThreadNamePrefix("async-service-"); // rejection-policy:当pool已经达到max size的时候,如何处理新任务 // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //执行初始化 executor.initialize(); return executor; } } /** * @ClassName TestServiceImpl * @date 2021/7/15 10:05 * @Description 需要的方法上使用线程池,打印当前线程,对比 * @Author bXiua * @Version 1.0 */ @Service @Slf4j public class TestServiceImpl implements TestService { @Autowired private ExecutorConfig executorConfig; @Override @Async public void run() throws InterruptedException { System.out.println("开始休眠"); TimeUnit.SECONDS.sleep(10); log.info("当前线程",Thread.currentThread().getName()); System.out.println("恢复"); } }
-
切面,使用的是代理,可以看成接口的实现类,无特殊情况,切面方法和织入点的方法是线性执行的,可以用作权限拦截;
-
但如果在切面方法,before或者after上加上@Async注解,开启异步线程,切面方法和织入点方法是异步执行的,就起不到拦截作用 ,但是操作日志记录用此类方法;
-
切面基本使用
/**
* @ClassName ThreadAspect
* @date 2021/7/15 10:26
* @Description 开启切面
* @Author bXiua
* @Version 1.0
*/
@Aspect
@Component
@Async
@Slf4j
public class ThreadAspect {
@Before("execution(* com.example.demo.TestController.*(..))")
public void beforeLogin() {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("当前线程",Thread.currentThread().getName());
System.out.println("前置通知");
}
}
-
配置织入点
// 配置织入点 @Pointcut("execution(* com.example.demo.TestController.*(..))") public void logPointCut(){ } // 使用织入点 //在本类的login执行之前 @Before("logPointCut()") public void beforelogin(JoinPoint joinPoint) { // 获取方法上的注解 Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); RequestMapping annotation = method.getAnnotation(RequestMapping.class); } //在本类的login执行之后执行 @After("logPointCut()") public void afterlogin(){ System.out.println("after"); }
-
使用annotation
-
添加自定义注解
-
使用切入点
-
需要的方法上添加注解即可
-
// 自定义注解
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
public String value() default "";
}
// 配置织入点
@Pointcut("@annotation(com.example.demo.annotation.Log)")
public void logPointCut(){
}
@Before("logPointCut()")
public void beforelogin()
{
System.out.println("before");
}
//在本类的login执行之后执行
@After("logPointCut()")
public void afterlogin(){
System.out.println("after");
}
常见切面表达式
1 所有公有方法的执行
execution(public * *(..))
2 所有以set开头的公有方法的执行
execution(* set*(..))
3 AccountService接口下的所有方法的执行
execution(* com.xyz.service.AccountService.*(..))
4 com.xyz.service包下的所有方法的执行
execution(* com.xyz.service.*.*(..))
5 com.xyz.service包及其子包下的所有方法的执行
execution(* com.xyz.service..*.*(..))
6 匹配com.xyz.service包下的所有类的所有方法(不含子包)
within(com.xyz.service.*)
7 com.xyz.service包和子包的所有方法
within(com.xyz.service..*)
8 匹配AccountService的代理类(不支持通配符)
this(com.xyz.service.AccountService)