【问题标题】:Spring Boot not injecting Bean with web aware scopeSpring Boot 不注入具有 Web 感知范围的 Bean
【发布时间】:2020-03-18 19:28:56
【问题描述】:

如果我尝试注入具有 Web 感知范围(即会话范围、请求范围)的 bean,则注入器会忽略该 bean。不调用 bean 方法和对象构造函数。这只发生在我声明的类中,因为我可以为标准库类型(例如 List 或 Map)注入会话范围的 bean。此外,如果我使用单例或原型作用域,注入也能正常工作。

有人可以解释这种奇怪的行为吗?我创建了一个准系统示例来演示该问题。 (我也尝试过搜索,但找不到遇到此问题的人。)

我想注入的类

public class CustomObj{
    public String field;

    public CustomObj(){
        System.out.println("CustomObj constructor called");
    }
}

配置文件

@Configuration
public class Config {

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public List<String> userValues() {
        List<String> list = new ArrayList<String>();
        list.add("This gets initialized");
        return list;
    }

    @Bean
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public CustomObj customObj() {
        CustomObj obj = new CustomObj();
        obj.field = "This doesn't";
        return obj;
    }
}

控制器注入对象

@RestController
@RequestMapping("/test")
public class TestController{

    @Autowired
    List<String> userValues;

    @Autowired
    CustomObj customObj;

    @RequestMapping("/pleasework")
    public String please(){
        return "List values: "+Arrays.toString(this.userValues.toArray())
            + " Obj value: "+this.customObj.field;
    }
}

主要

@SpringBootApplication
public class SessionbeansApplication {

    public static void main(String[] args) {
        SpringApplication.run(SessionbeansApplication.class, args);
    }

}

访问 /test/pleasework 会得到输出 List values: [This gets initialized] Obj value: null,表明 List 已正确注入,但 CustomObj 未正确注入。

【问题讨论】:

    标签: java spring spring-boot configuration


    【解决方案1】:

    如果您运行您的代码,输出将类似于List values: [This gets initialized] Obj value: null

    您没有得到NullpoiterException,这意味着您的CustomObj-bean 已创建

    您应该在 CustomObj 中使用 getter 和 setter。 并使用 getter 访问字段:this.customObj.getField();

        @RequestMapping("/pleasework")
        public String please(){
            System.out.println(userValues +  " and " + customObj);
            return "List values: "+ Arrays.toString(this.userValues.toArray())
                    + " Obj value: " + this.customObj.getField();// <--- use getter
        }
    

    CustomObj 中添加toString() 也可以

    class CustomObj {
        public String field;
    
        public CustomObj(){
            System.out.println("CustomObj constructor called");
        }
    
        @Override
        public String toString() {
            return "CustomObj{" +
                    "field='" + field + '\'' +
                    '}';
        }
    }
    
    ....
    
      @RequestMapping("/pleasework")
        public String please(){
            System.out.println(userValues +  " and " + customObj);
            return "List values: "+ Arrays.toString(this.userValues.toArray())
                    + " Obj value: " + this.customObj; //<---- use toString()
        }
    
    

    【讨论】:

    • 我很困惑,因为这个答案有点误导。问题不是 NullPointerException,而是注入器忽略了 bean。但是,您的解决方案确实有效。如果我使用 getter 和 setter,注入器会在断点处初始化 bean。你知道为什么会这样吗?
    • 你没有得到一个空指针,所以你的 bean 是自动装配的。只需尝试打印this.customObj,您将在页面上获得输出
    • 我同意我没有得到空指针,但 bean 绝对不是从原始代码自动装配的。在原始代码中,Config 中的 bean 方法被完全忽略了。没有命中任何打印语句或断点。但是,如果我像您建议的那样使用 getter 和 setter,它确实会自动装配。我很困惑为什么添加 setter 可以让我的对象被注入
    • 如果我使用您的代码,我会在页面中收到“列表值:[已初始化] Obj 值:null”,但控制台会打印:“调用了 CustomObj 构造函数”......所以 CustomObj被注入
    • 这很奇怪,因为它不会发生在我身上。我会接受你的回答,因为它确实导致我的代码工作,即使它看起来对我有误导。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2017-04-25
    • 1970-01-01
    • 2016-06-21
    • 2011-05-06
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多