前言
考完计网和人智基础,好像大二浑浑噩噩就这样过去了,坐了两天火车回家,这几天静下心来把之前的项目给消化一下。
线程变量
有些时候一个线程可能在不同的类方法之间来回调用,调用的时候可能需要重复携带多次相同的变量,这时候我们希望将该变量定义为全局,减少码量的同时项目结构会更清晰,但我们的项目一般是在多线程高并发场景下运行的,这时候线程之间对这个变量的定义可能并不相同,如果我们使用全局变量,线程之间共享这个变量,那我们怎么知道使用的是不是自己定义的变量呢,ThreadLocal给我们提供了一种解决方案。
ThreadLocal是什么
ThreadLocal就是线程变量,为每个线程所拥有,对其他线程保持隔离。
它是怎么实现的呢?
简单来说,你的进程维护了一个Map,这个Map将ThreadLocal作为key存入,其中的value是我们自定义的数据,可以是Integer、String等各种类型,这里只是很简单的描述,详细源码可以看JavaGuide中关于ThreadLocal的介绍。
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class ThreadLocaDemo { private static ThreadLocal<String> localVar = new ThreadLocal<String>(); static void print(String str) { System.out.println(str + " :" + localVar.get()); localVar.remove(); } public static void main(String[] args) throws InterruptedException { new Thread(new Runnable() { public void run() { ThreadLocaDemo.localVar.set("local_A"); print("A"); System.out.println("after remove : " + localVar.get()); } },"A").start(); Thread.sleep(1000); new Thread(new Runnable() { public void run() { ThreadLocaDemo.localVar.set("local_B"); print("B"); System.out.println("after remove : " + localVar.get()); } },"B").start(); } } A :local_A after remove : null B :local_B after remove : null
|
在项目中的使用
介绍一种token技术和ThreadLocal结合使用的场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class BaseContext {
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id) { threadLocal.set(id); }
public static Long getCurrentId() { return threadLocal.get(); }
public static void removeCurrentId() { threadLocal.remove(); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
String token = request.getHeader(jwtProperties.getAdminTokenName());
try { log.info("jwt校验:{}", token); Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token); Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString()); BaseContext.setCurrentId(empId); log.info("当前员工id:", empId); return true; } catch (Exception ex) { response.setStatus(401); return false; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
@Override public void insert(EmployeeDTO employeeDTO) { Employee employee = new Employee(); BeanUtils.copyProperties(employeeDTO, employee);
employee.setUpdateTime(LocalDateTime.now()); employee.setCreateTime(LocalDateTime.now());
employee.setStatus(StatusConstant.ENABLE);
employee.setPassword(DigestUtils.md5DigestAsHex(DEFAULT_PASSWORD.getBytes()));
employee.setCreateUser(BaseContext.getCurrentId()); employee.setUpdateUser(BaseContext.getCurrentId());
employeeMapper.insert(employee); }
|
全局异常处理器
有时候写项目,我们会使用try-catch不断将异常捕获,这也是对异常的一种处理方式,但是用户在使用的时候出现问题,他自己是看不到出现的异常的,我们只是捕获异常却没有进行处理,如果在每一次捕获中都对异常进行一次处理,工作量将变得巨大(面向对象变为面向异常,总之Springboot对此提供了一个很好的全局处理器。SpringBoot中,@ControllerAdvice 即可开启全局异常处理,使用该注解表示开启了全局异常的捕获,我们只需在自定义一个方法使用@ExceptionHandler注解然后定义捕获异常的类型即可对这些捕获的异常进行统一的处理。
原理咱们先不做讨论(纯不会
这是一个简单的处理sql重复字段的处理器,我们希望给用户返回重复提醒
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
@RestControllerAdvice @Slf4j public class GlobalExceptionHandler {
@ExceptionHandler public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){ String message = ex.getMessage(); if(message!=null && message.contains("Duplicate entry")){ String[] split = message.split(" "); String username = split[2]; String msg = username + MessageConstant.ALREADY_EXISETS; return Result.error(msg); }else{ return Result.error(MessageConstant.UNKNOWN_ERROR); } } }
|
参考