首页 > 其他分享 >2024.11.12

2024.11.12

时间:2024-11-12 22:58:07浏览次数:1  
标签:2024.11 依赖 SecurityHandler private getUser 12 user UserService

主要问题:

SecurityHandlerhandlerOnAuthenticationSuccess 方法中调用了 userService.userLoginStatus,这会导致 UserService 需要依赖 SecurityHandler。这种双向依赖形成了一个循环依赖,Spring 容器无法正确处理这个循环,导致应用启动失败。

解决思路:

1. 避免循环依赖

通过重构代码,消除这种循环依赖。常见的做法是将其中某个依赖提取出来,或改变它们的关系。以下是几种可能的解决方法:

方法 1:延迟加载 UserService

如果 UserService 仅在 SecurityHandler 中的某些方法中使用,你可以使用 @Lazy 注解来延迟加载 UserService,从而避免循环依赖。

代码修改如下:

@Component
@RequiredArgsConstructor
public class SecurityHandler {

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private RedisCache redisCache;

    @Resource
    private LoginLogService loginLogService;

    @Resource
    @Lazy  // 延迟加载,避免循环依赖
    private UserService userService;

    public void handlerOnAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            LoginUser user
    ) {
        String typeHeader = request.getHeader(Const.TYPE_HEADER);
        if ((!StringUtils.matches(typeHeader, List.of(Const.BACKEND_REQUEST, Const.FRONTEND_REQUEST)) && user.getUser().getRegisterType() == 1)) {
            throw new BadCredentialsException("非法请求");
        }
        Long id = user.getUser().getId();
        String name = user.getUser().getUsername();
        // UUID做jwt的id
        String uuid = UUID.randomUUID().toString();
        // 生成jwt
        String token = jwtUtils.createJwt(uuid, user, id, name);

        // 转换VO
        AuthorizeVO authorizeVO = user.getUser().asViewObject(AuthorizeVO.class, v -> {
            v.setToken(token);
            v.setExpire(jwtUtils.expireTime());
        });
        
        // 如果可以,尽量避免这里直接调用 UserService 的方法,改成通过事件或消息中间件等方式解耦
        userService.userLoginStatus(user.getUser().getId(), user.getUser().getRegisterType());
        
        loginLogService.loginLog(request, request.getParameter(USER_NAME), 0, RespConst.SUCCESS_LOGIN_MSG);
        WebUtil.renderString(response, ResponseResult.success(authorizeVO, RespConst.SUCCESS_LOGIN_MSG).asJsonString());
    }
}

使用 @Lazy 注解后,UserService 在初始化时不会立即注入,而是等到需要时才会被注入,从而避免了构造时的循环依赖问题。

方法 2:重构 SecurityHandlerUserService 的依赖关系

另一种方式是重构 SecurityHandlerUserService 的关系,避免它们之间直接的依赖。如果 UserServiceSecurityHandler 中有互相依赖的功能,可以考虑通过引入一个新的中间服务来拆解这两个类之间的关系。例如,将 userLoginStatus 方法移到一个新的业务类中,而不是放在 UserService 中。

@Service
public class UserStatusService {

    private final UserService userService;

    @Autowired
    public UserStatusService(UserService userService) {
        this.userService = userService;
    }

    public void updateUserLoginStatus(Long userId, int registerType) {
        // 这里执行用户登录状态更新
        userService.userLoginStatus(userId, registerType);
    }
}

@Component
@RequiredArgsConstructor
public class SecurityHandler {

    @Resource
    private JwtUtils jwtUtils;

    @Resource
    private RedisCache redisCache;

    @Resource
    private LoginLogService loginLogService;

    @Resource
    private UserStatusService userStatusService;

    public void handlerOnAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            LoginUser user
    ) {
        String typeHeader = request.getHeader(Const.TYPE_HEADER);
        if ((!StringUtils.matches(typeHeader, List.of(Const.BACKEND_REQUEST, Const.FRONTEND_REQUEST)) && user.getUser().getRegisterType() == 1)) {
            throw new BadCredentialsException("非法请求");
        }
        Long id = user.getUser().getId();
        String name = user.getUser().getUsername();
        // UUID做jwt的id
        String uuid = UUID.randomUUID().toString();
        // 生成jwt
        String token = jwtUtils.createJwt(uuid, user, id, name);

        // 转换VO
        AuthorizeVO authorizeVO = user.getUser().asViewObject(AuthorizeVO.class, v -> {
            v.setToken(token);
            v.setExpire(jwtUtils.expireTime());
        });

        // 使用新的 UserStatusService 来处理登录状态
        userStatusService.updateUserLoginStatus(user.getUser().getId(), user.getUser().getRegisterType());

        loginLogService.loginLog(request, request.getParameter(USER_NAME), 0, RespConst.SUCCESS_LOGIN_MSG);
        WebUtil.renderString(response, ResponseResult.success(authorizeVO, RespConst.SUCCESS_LOGIN_MSG).asJsonString());
    }
}

在这种方式下,SecurityHandler 不再直接依赖 UserService,而是依赖 UserStatusService,从而打破了循环依赖。

方法 3:使用事件驱动方式

如果 userService.userLoginStatus() 是一个异步操作或者涉及到其他业务逻辑,可以考虑使用 Spring 的 事件驱动模型 来解耦这个过程。你可以发布一个事件,并在另一个类中监听这个事件来执行相关逻辑。这样可以进一步解耦类与类之间的依赖关系。

总结:

  • 使用 @Lazy 注解:最简单的一种解决循环依赖的方法,适用于延迟加载的场景。
  • 重构依赖关系:将一个类中的某些依赖移到其他服务中,避免直接的循环依赖。
  • 事件驱动:如果操作是异步的,可以考虑通过发布/订阅机制来解耦操作。

标签:2024.11,依赖,SecurityHandler,private,getUser,12,user,UserService
From: https://www.cnblogs.com/258-333/p/18542825

相关文章

  • 11.12随笔
    这里是11.12随笔。作业留档:本题要求实现一个函数,将给定单向链表逆置,即表头置为表尾,表尾置为表头。链表结点定义如下:structListNode{intdata;structListNode*next;};函数接口定义:structListNode*reverse(structListNode*head);其中head是用户传入的链表的头指针......
  • 【划重点】一文搞懂Webpack环境区分配置(12)
    在实际开发中,我们经常需要针对生产环境和开发环境分别书写webpack配置。为了更好地适应这种需求,webpack允许配置不仅可以是一个对象,还可以是一个函数。这样,开发者可以根据不同的环境返回不同的配置对象。1.使用函数作为配置module.exports=env=>{return{......
  • Solution - Codeforces 1217E Sum Queries?
    对于这个“好的”的判定条件看起来有点奇怪,不妨结合上题目要求的“最小\(sum\)”一起考虑。因为要最小化\(s_p\),所以一个比较直观的想法是先从选的数个数入手。考虑到如果选的只有\(1\)个数\(a_i\),那么\(sum=a_i\),一定是好的,排除。如果选的是\(2\)个数\(a_i,a_j\),......
  • SS241112A. 定向越野(walk)
    SS241112A.定向越野(walk)题意给你\(n\)个点,\(n\le12\),你可以从任意一个点出发以任意顺序依次遍历所有点燃火回到起点,你只能拐直角走,问最小路程。答案输出最小路程的平方,输出分数形式。可以证明最小路程的平方一定是有理数。思路显然枚举遍历顺序。首先需要明白为什么答案......
  • 11.12
    贺了好多道AT之后发现自己瞎猜的能力有所提升!!!11.11A.开场二十多分钟猜了个结论,感觉很对。由于只有一个小样例且题面没说有自环甚至暗示没有自环且数据故意造自环最后挂成了20分。最后环一定是每个点的读书都为\(2\),所以对于度数大于\(2\)的我们要对它进行一次拆,若度数......
  • 每日打开 11.12
    [AHOI2021初中组]超市购物题目背景AHOI2021初中组T1你可以选择跳过背景部分。春的一天,正是乍暖还寒时候,狂风乍起。小可可裹紧了单薄的外衣,往小雪家中赶去。“今天真不是个出门的时候啊!”小可可感叹道。“但是我还有东西要买……你就陪我去下超市吧?”在超市里,小雪一共买......
  • [考试记录] 2024.11.12 noip模拟赛11
    T1使用\(bfs\)记录走到\(tx,ty\)的路径的横边和竖边的数量,然后取\(\max\)。这里取\(\max\)的原因是,找到的路径必须是最短路,当\(k\)取的小的时候竖边就会变多,所以这条路径就不一定是最短路了。#include<bits/stdc++.h>usingnamespacestd;#defineppair<int,int>i......
  • 2024/11/12日 日志 关于Servlet ---- Request(请求)& Response(响应) 的补充
    Request(请求)&Response(响应)--·Request:获取请求数据--·Response:设置响应数据Request点击查看代码--Request继承体系--ServletRequestJava提供的请求对象根接口--HttpServletRequestJava提供的对Http协议封装的请求对象接口--RequestFacade......
  • 2024.11.12 1842版
    起于《海奥华预言》的思考◆地球管理结构和参考持续更新中...... 英文地址:https://github.com/zhuyongzhe/Earth/tags中文地址:https://www.cnblogs.com/zhuyongzhe85作者:朱永哲 ---------------------------------------------------------------------------------......
  • 20241112 模拟赛总结
    期望得分:100+100+0+10=210实际得分:100+80+0+10=190好困。。T1被硬控了很久。看着就像诈骗题,观察大样例发,答案就是\(a_1-a_2\),特判\(n=1\)的情况。证明的话,感觉就是后面的数,贡献成正数和负数应该是数量相同的,所以就抵消了,第一个数只能贡献成正数,第二个数只能贡献成负的。T......