You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让@Service类通过new实例化并解决Autowired字段为空问题

解决方案

一、修复UserContext的依赖注入问题

放弃使用@Configurable,采用以下两种更可靠的方式:

方式1:通过Spring管理的RoleFactory创建UserContext

  1. 给RoleFactory添加@Component注解,让Spring容器接管它的生命周期;
  2. 在RoleFactory中通过构造函数注入UserService和所有Role实现类,Spring会自动收集同类型的Bean:
@Component
public class RoleFactory {
    private final UserService userService;
    private final List<Role> roleList;

    public RoleFactory(UserService userService, List<Role> roleList) {
        this.userService = userService;
        this.roleList = roleList;
    }

    public Role getRoleByType(String roleType) {
        return roleList.stream()
                .filter(role -> role.getType().equals(roleType))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("无效角色类型"));
    }

    public UserContext createUserContext(String roleType) {
        Role targetRole = getRoleByType(roleType);
        return new UserContext(userService, targetRole);
    }
}
  1. UserContext改为普通类,通过构造函数接收UserService和Role实例:
public class UserContext {
    private final UserService userService;
    private Role currentRole;

    public UserContext(UserService userService, Role currentRole) {
        this.userService = userService;
        this.currentRole = currentRole;
    }

    public void executeTargetAction() {
        currentRole.handleAction(userService);
    }
}
  1. 控制器中注入RoleFactory,获取当前用户角色后创建UserContext:
@RestController
@RequestMapping("/users")
public class UserController {
    private final RoleFactory roleFactory;

    public UserController(RoleFactory roleFactory) {
        this.roleFactory = roleFactory;
    }

    @GetMapping("/operate")
    public ResponseEntity<?> doOperate() {
        // 从SecurityContextHolder获取当前用户角色
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        UserPrincipal principal = (UserPrincipal) auth.getPrincipal();
        String userRole = principal.getRole();
        
        UserContext context = roleFactory.createUserContext(userRole);
        context.executeTargetAction();
        return ResponseEntity.ok().build();
    }
}

方式2:让Role实现类成为Spring Bean,直接注入UserService

  1. 给所有Role实现类(如UserRole)添加@Component注解;
  2. 在Role实现类中直接注入UserService:
@Component
public class UserRole implements Role {
    private final UserService userService;

    public UserRole(UserService userService) {
        this.userService = userService;
    }

    @Override
    public void handleAction() {
        userService.processUserLogic();
    }
}
  1. UserContext简化为仅接收Role实例:
public class UserContext {
    private Role currentRole;

    public UserContext(Role currentRole) {
        this.currentRole = currentRole;
    }

    public void executeTargetAction() {
        currentRole.handleAction();
    }
}
  1. 控制器中通过ApplicationContext或RoleFactory获取对应Role实例,创建UserContext。

二、解决直接new UserService的问题

  1. 彻底删除所有new UserService()的写法:Service必须由Spring容器管理,所有需要使用UserService的场景按以下方式处理:
    • 若调用类是Spring管理的(如@Component、@Controller标记的类),直接通过构造函数注入UserService;
    • 若调用类不是Spring管理的(如ClassGetModel),要么给该类添加@Component转为Spring组件,要么在调用它的地方注入UserService,通过构造函数或方法参数传递进去:
      // 将ClassGetModel转为Spring组件
      @Component
      public class ClassGetModel {
          private final UserService userService;
      
          public ClassGetModel(UserService userService) {
              this.userService = userService;
          }
      
          // 使用userService的业务方法
      }
      
  2. 无需手动编写UserService的全参构造函数,Spring会自动处理所有依赖的注入,避免参数过多的麻烦。

三、优化状态模式的角色系统

  • 所有Role实现类交由Spring管理,通过@Component标记,Spring会自动收集所有Role实现类并注入到RoleFactory的List<Role>中,无需手动维护角色列表;
  • 杜绝在非Spring管理类中直接创建Service或Role实例,确保所有依赖都通过Spring容器注入,保证依赖完整性。

内容的提问来源于stack exchange,提问作者Cross

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 06:35:18