ThreadLocal在项目中的简单使用

ThreadLocal在项目中的简单使用

什么是threadlocal?

ThreadLocal是Java提供的一种线程局部变量,它能够实现线程之间的数据隔离,即每个线程访问自己内部的一个变量副本。在多线程编程中,ThreadLocal非常有用,主要用于保持线程安全,避免对公共变量的共享,从而避免潜在的线程安全问题。

使用场景有哪些

1、用户身份认证信息存储:将当前登录用户的信息存储在ThreadLocal中,确保在一个线程内的任何地方都能安全地访问当前用户的信息,而不会被其他线程的用户信息所干扰。

2、数据库连接管理:在使用数据库连接池时,可以使用ThreadLocal来存储每个线程的数据库连接对象,确保在同一线程中的不同方法里可以重用同一个数据库连接,从而避免频繁地打开和关闭连接。

3、事务管理:在处理事务时,可以通过ThreadLocal来保存当前线程的事务状态,确保在事务处理过程中的多个操作都在同一个事务上下文中执行。

4、线程安全的数据格式化:例如,在多线程环境下使用SimpleDateFormat类时,由于它不是线程安全的,可以使用ThreadLocal为每个线程维护一个SimpleDateFormat实例,从而避免线程安全问题。

5、性能监控和日志记录:在进入和退出方法时,可以通过ThreadLocal来存储方法执行的起始时间,以便计算方法的执行时间。此外,也可以存储线程执行的上下文信息,用于日志记录和性能监控。

6、Spring事务管理:Spring框架在管理事务时,会将当前事务的状态保存在ThreadLocal中,这样在事务的整个生命周期内,无论是在哪个层次的方法中,都能获取到同一个事务状态。

实战上代码:

创建拦截器:

package com.xx.xx.interceptors;

import com.xx.entity.SysUserEntity;
import com.xx.dto.SysUserDto;
import com.xx.xx.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author psd 登录拦截器,用于存储用户信息
 */
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private SysUserService sysUserService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取当前登录人的信息
        SysUserEntity userEntity = sysUserService.querySysUserEntityByDto(SysUserDto.builder().account(request.getParameter("accountNumber")).build());
        UserContext.setUserThreadLocal(userEntity);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
       	// 显式地调用ThreadLocal.remove()方法来清理这些数据。
        UserContext.clearUserThreadLocal();
    }

}

配置拦截器的拦截地址:

package com.xx.xx.platform.interceptors;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author psd 配置拦截器
 */
@Configuration
@Slf4j
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        log.info("开始执行WebMvcConfig==============================");
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**/check/sysuser/querySysUserTask");
    }
}

用于存放和获取线程局部变量中的用户信息。

package com.dx.major.platform.interceptors;

import com.dx.major.platform.entity.SysUserEntity;

/**
 * @author psd 用于存放和获取ThreadLocal中的用户信息
 */
public class UserContext {

    /**
     * 用户信息
     */
    public static final ThreadLocal<SysUserEntity> USER_THREAD_LOCAL = new ThreadLocal<>();

    /**
     * 获取用户信息
     * 
     * @return 用户信息
     */
    public static SysUserEntity getUser() {
        return USER_THREAD_LOCAL.get();
    }

    /**
     * 设置用户信息
     * 
     * @param sysUserEntity
     *            用户信息
     */
    public static void setUserThreadLocal(SysUserEntity sysUserEntity) {
        USER_THREAD_LOCAL.set(sysUserEntity);
    }

    /**
     * 删除用户信息
     */
    public static void clearUserThreadLocal() {
        USER_THREAD_LOCAL.remove();
    }

}

执行流程:
1、拦截以check/sysuser/querySysUserTask 结尾的路径,
2、设置用户信息到线程局部变量里面
3、线程执行完毕后,移除线程局部变量里面的值

注意事项:
1,必须是可以拦截的地址,才会被拦截器拦截
2,请求参数中必须有指定的参数,否则在获取threadlocal里面的数据时候为null,报空指针异常

喜欢我的文章的话,点个阅读或者点个点赞,是我编写博客的动力,持续更新中

你可能感兴趣的:(java)