Spring启动 - 会话作用域组件的setter不能使用单件服务 - 字段为空

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring启动 - 会话作用域组件的setter不能使用单件服务 - 字段为空相关的知识,希望对你有一定的参考价值。

我在Spring Boot中的REST控制器后面有一个简单的服务。该服务是一个单例(默认情况下),我正在自动装配一个会话范围的bean组件,用于存储会话首选项信息并尝试从服务中填充其值。我在自动装配的组件上调用setter,但我设置的字段保持为空并且不会更改。

尝试过使用和不使用龙目岛的豆子;还有和没有在FooPref上实现Serializable;还将属性从FooPrefs复制到另一个DTO并返回它;还通过@Autowired注入以及@Inject构造函数注入。在所有这些情况下,字段保持为空。

使用spring-boot-starter-web运行Spring Boot(spring-boot-starter-parent)1.5.6.RELEASE,Java 8。

会话范围的组件:

@Component
@SessionScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
@Data
@NoArgsConstructor
public class FooPrefs implements Serializable {
    private String errorMessage;
    private String email;
    private String firstName;
    private String lastName;
}

REST控制器:

@RestController
@RequestMapping("/api/foo")
public class FooController {

    @Autowired
    private FooPrefs fooPrefs;

    private final FooService fooService;

    @Inject
    public FooController(FooService fooService) {
        this.fooService = fooService;
    }

    @PostMapping(value = "/prefs", consumes = "application/json", produces = "application/json")
    public FooPrefs updatePrefs(@RequestBody Person person) {
        fooService.updatePrefs(person);

        // These checks are evaluating to true
        if (fooPrefs.getEmail() == null) {
            LOGGER.error("Email is null!!");
        }
        if (fooPrefs.getFirstName() == null) {
            LOGGER.error("First Name is null!!");
        }
        if (fooPrefs.getFirstName() == null) {
            LOGGER.error("First Name is null!!");
        }
        return fooPrefs;
    }
}

服务:

@Service
@Scope(value = "singleton")
@Transactional(readOnly = true)
public class FooService {

    @Autowired
    private FooPrefs fooPrefs;

    @Inject
    public FooService(FooRepository fooRepository) {
        this.fooRepository = fooRepository;
    }

    public void updatePrefs(Person person) {
        fooRepository.updatePerson(person);

        //the fields below appear to getting set correctly while debugging in the scope of this method call but after method return, all values on fooPrefs are null
        fooPrefs.setEmail(person.getEmail());
        fooPrefs.setFirstName(person.getFirstName());
        fooPrefs.setLastName(person.getLastName());
    }
}
答案

我发现了我的问题。字段被添加到我的FooPrefs会话管理对象中,并破坏了我的客户端。这些setter实际上正在工作,并被一些错误处理代码排除在外。

以下编辑修复了JSON序列化问题:

会话范围的组件(无更改)

新Dto

@Data
@NoArgsConstructor
public class FooPrefsDto {
    private String errorMessage;
    private String email;
    private String firstName;
    private String lastName;
}

控制器(更新)

@RestController
@RequestMapping("/api/foo")
public class FooController {

    private final FooService fooService;

    @Inject
    public FooController(FooService fooService) {
        this.fooService = fooService;
    }

    @PostMapping(value = "/prefs", consumes = "application/json", produces = "application/json")
    public FooPrefsDto updatePrefs(@RequestBody Person person) {
        FooPrefsDto result = fooService.updatePrefs(person);

        // results coming back correctly now
        if (result.getEmail() == null) {
            LOGGER.error("Email is null!!");
        }
        if (result.getFirstName() == null) {
            LOGGER.error("First Name is null!!");
        }
        if (result.getFirstName() == null) {
            LOGGER.error("First Name is null!!");
        }
        return result;
    }
}

服务(更新)

@Service
@Scope(value = "singleton")
@Transactional(readOnly = true)
public class FooService {

    @Autowired
    private FooPrefs fooPrefs;

    @Inject
    public FooService(FooRepository fooRepository) {
        this.fooRepository = fooRepository;
    }

    public FooPrefsDto updatePrefs(Person person) {
        fooRepository.updatePerson(person);

        //the fields below appear to getting set correctly while debugging in the scope of this method call but after method return, all values on fooPrefs are null
        fooPrefs.setEmail(person.getEmail());
        fooPrefs.setFirstName(person.getFirstName());
        fooPrefs.setLastName(person.getLastName());
        return getFooPrefsDto();
    }

    private FooPrefsDto getFooPrefsDto() {
        FooPrefsDto retDto = new FooPrefsDto();
        retDto.setEmail(fooPrefs.getEmail());
        retDto.setLastName(fooPrefs.getLastName());
        retDto.setFirstName(fooPrefs.getFirstName());
        return retDto;
    }
}

以上是关于Spring启动 - 会话作用域组件的setter不能使用单件服务 - 字段为空的主要内容,如果未能解决你的问题,请参考以下文章

Spring Bean作用域实例

spring:使用会话和请求作用域

Spring框架参考手册(4.2.6版本)翻译——第三部分 核心技术 6.5.4 请求(request)会话(session)和全局会话(global session)作用域

spring:bean的作用域

Spring实战Bean 的作用域

Spring实战407---Bean的作用域