原型 Bean 未按预期自动布线

2022-09-01 15:37:26

测试控制器.java

@RestController
public class TestController {

    @Autowired
    private TestClass testClass;

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public void testThread(HttpServletResponse response) throws Exception {
        testClass.doSomething();
    }
}

测试类.java

@Component
@Scope("prototype")
public class TestClass {

    public TestClass() {
        System.out.println("new test class constructed.");
    }

    public void doSomething() {

    }

}

如您所见,我正在尝试确定在访问“xxx/test”时是否注入了新的。 只打印了一次(第一次我触发“xxx/test”),而我期望它打印得一样。这个均值对象只能是吗?那么如何运作呢?TestClass"new test class constructed."@Autowired@Singleton@Scope

编辑:

测试控制器.java

@RestController
public class TestController {

    @Autowired
    private TestClass testClass;

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public void testThread(HttpServletResponse response) throws Exception {
        testClass.setProperty("hello");
        System.out.println(testClass.getProperty());
    }
}

我尝试了解决方案,注册为.这是我访问“xxx/test”时的三次结果@Valerio VaudiScope(scopeName = "request")

(第一次)

  • 构建了新的测试类。

(秒)

(第三)

我不明白为什么结果是空的,因为它不会在每次使用它时重建一个新的结果。

然后我尝试了解决方案:@Nikolay Rusev@Scope("prototype")

(第一)

  • 新建成的。
  • 新建成的。

(秒)

  • 新建成的。
  • 新建成的。

(第三)

  • 新建成的。
  • 新建成的。

这很容易理解,因为每次我使用它(TestClass)时,Spring都会自动重新生成它的新实例。但是第一个场景我仍然无法理解,因为它似乎只为每个请求保留一个新实例。

真正的目的是:在每个请求生命周期中,都需要一个新的(如果需要),并且只需要一个。目前,似乎只有解决方案是可行的(我已经知道),但我只想知道这是否可以通过使用+ +自动完成。testClassApplicationContext@Component@Scope@Autowired


答案 1

以上所有答案都是正确的。控制器默认为,注入的实例化一次,因为默认作用域代理模式来自spring docsingletontestClassDEFAULT

公共抽象 ScopedProxyMode proxyMode 指定是否应将组件配置为作用域代理,如果是,则代理应是基于接口还是基于子类。默认值为 ScopedProxyMode.DEFAULT,这通常表示不应创建作用域内代理,除非在组件扫描指令级别配置了不同的默认值。

类似于Spring XML中的支持。

另请参阅:ScopedProxyMode Default: org.springframework.context.annotation.ScopedProxyMode.DEFAULT

如果您希望每次需要时都注入新实例,则应将TestClass

@Component
@Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class TestClass {

    public TestClass() {
        System.out.println("new test class constructed.");
    }

    public void doSomething() {

    }

}

使用此附加配置,注入的将不是真正的bean,而是bean的代理,并且此代理将了解范围,并将在每次需要时返回新实例。testClassTestClassTestClassprototype


答案 2

如前所述,控制器默认为单例,这就是为什么实例化和注入仅在创建时执行一次的原因。TestClass

解决方案可以是注入应用程序上下文并手动获取Bean:

@RestController
public class TestController {

    @Autowired
    ApplicationContext ctx;

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public void testThread(HttpServletResponse response) throws Exception {
        ((TestClass) ctx.getBean(TestClass.class)).doSomething();
    }
}

现在,当请求一个bean时,Spring知道它是,将创建一个新实例并返回它。TestClass@Prototype

另一种解决方案是使控制器 。@Scope("prototype")


推荐