【问题标题】:Spring Boot : Sharing a bean between different componentsSpring Boot:在不同组件之间共享一个 bean
【发布时间】:2020-01-05 15:19:41
【问题描述】:

我有一个 bean,我在我的 bean 配置中声明如下:

@Configuration
public class BeanConfig {
    @Bean
    public MemberDTO getMemberDTO() {
        return new MemberDTO();
    }
}

当用户调用我的服务时,我使用他们提供的用户名和密码来调用不同服务的端点以获取用户的信息:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    private static final Logger LOGGER = LogManager.getLogger(CustomAuthenticationProvider.class);

    private @Autowired MemberDTO memberDTO;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String loginGeniuneFailMessage = "";
        boolean loginGeniuneFail = false;
        try {
            String username = authentication.getName();
            String password = authentication.getCredentials().toString();

            String endPoint = credentialsBaseUrl + "/api/login";

            HttpResponse<MemberDTO> response_auth = Unirest.get(endPoint)
                    .basicAuth(username, password)
                    .header("Accept", "*/*")
                    .asObject(MemberDTO.class);

            int status_auth = response_auth.getStatus();

            if (status_auth == 200) {
                if (response_auth.getBody() == null) {
                    LOGGER.info("account validation - could not parse response body to object");

                    UnirestParsingException ex = response_auth.getParsingError().get();
                    LOGGER.error("parsing error: ", ex);
                } else {
                    memberDTO = response_auth.getBody();
                }
            }

            ...
        } catch (Exception ex) {
            ...
        }
    }

我想将用户的信息存储在 memberDTO 中,并在不同组件的其他地方使用 memberDTO,而不是每次都调用登录 API:

@Component
public class MemberLogic {
    private @Autowired MemberDTO memberDTO;

    public ResponseEntity<?> processMemberInformation(WrapperDTO wrapperDTO, BindingResult result) {
        if (result.hasFieldErrors()) {
            String errors = result.getFieldErrors().stream()
                    .map(p -> p.getDefaultMessage()).collect(Collectors.joining("\n"));
            return ResponseEntity.badRequest().body("An error occured while trying to persist information: " + errors);
        }

        String name = memberDTO.getName();

        ...
    }
}

现在的问题是“memberDTO.getName()”返回 null,即使该值是在 CustomAuthenticationProvider 中的初始 API 调用中设置的。

我的问题是:为什么这不起作用?这是处理此类事情的最佳方法吗?

谢谢。

【问题讨论】:

  • 没有使用SecurityContext的具体原因是什么?
  • @chrylis-onstrike- 这与直接问题有关吗?
  • 基本上,您正在尝试存储有关登录用户的信息,并在应用程序需要的任何地方使用它。正如@chrylis-onstrike- 建议的那样,最好使用 SecurityContext 来存储登录的用户详细信息。这是在基于 Spring 的应用程序中获取登录用户详细信息的标准方法。
  • @NageswaraRaOMaridu 虽然这是处理用户信息的推荐方式,但它如何回答直接问题:为什么这不起作用?

标签: java spring spring-boot


【解决方案1】:

我的问题是:为什么这不起作用?这是处理此类事情的最佳方法吗?

这不起作用,因为 Java 使用 pass-by-value 语义而不是 pass-by-reference 语义。这意味着声明memberDTO = response_auth.getBody(); 并没有真正使Spring 容器开始指向response_auth.getBody() 返回的MemberDTO。它只会使CustomAuthenticationProvider 中的memberDTO 引用指向响应中的对象。 Spring 容器仍然继续引用原始的MemberDTO 对象。

解决此问题的一种方法是定义一个DAO 类,该类可用于与DTO 实例交互,而不是直接创建DTO bean:

@Configuration
public class BeanConfig {
    @Bean
    public MemberDAO getMemberDAO() {
        return new MemberDAO();
    }
}

CustomAuthenticationProvider 然后可以在MemberDAO 中设置MemberDTO,方法是:memberDAO.setMemberDTO(response_auth.getBody());

最后,MemberLogic 可以以String name = memberDAO.getMemberDTO().getName(); 的身份访问MemberDTO

注意:不是从MemberDAO 返回MemberDTOMemberDAO 可以定义一个名为getName 的方法,该方法从MemberDTO 中提取名称并返回它。 (告诉不要问原则)。也就是说,正如 cmets 中所建议的那样,最佳做法是使用 SecurityContext 来存储用户信息。

【讨论】:

  • 非常感谢!我做了一些研究,我能够按照建议使用 SecurityContext 来传递用户的额外详细信息,并在我的其他组件中检索这些详细信息
【解决方案2】:

问题是,您不能像 memberDTO = response_auth.getBody(); 那样覆盖 spring bean“内容”,因为它只更改给定 bean 的实例变量。 (而且它也不好,因为它超出了 Spring Boot 上下文并且它只覆盖了这个单例 bean 的字段依赖)

您不应该使用普通的 spring bean 来保存数据(状态)。默认情况下,所有 spring bean 都是单例的,您可能会遇到一些并发问题。

为此,您应该使用数据库,您可以在其中写入数据或类似会话 bean。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    相关资源
    最近更新 更多