Prototype Bean doesn't get autowired as expected

后端 未结 5 820
南旧
南旧 2021-02-05 04:14

TestController.java

@RestController
public class TestController {

    @Autowired
    private TestClass testClass;

    @RequestMapping(value = \"/test\", method         


        
相关标签:
5条回答
  • 2021-02-05 04:24

    As mentioned, controller is by default singleton, that's why instantiation and injection of TestClass is performed only once on its creation.

    Solution can be to inject application context and get the bean manually:

    @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();
        }
    }
    

    Now, when a TestClass bean is requested, Spring knowing that it is @Prototype, will create a new instance and return it.

    Another solution is to make the controller @Scope("prototype").

    0 讨论(0)
  • 2021-02-05 04:24

    Spring controllers are singletons by default (which is OK due to their stateless nature), as well as the other Spring beans.

    That's why it is enough to instantiate only one TestClass instance for the only TestController instance.

    It is easy to instantiate TestClass one more time - just inject it in another controller or get from the context programmatically

    0 讨论(0)
  • 2021-02-05 04:28

    all the answers above are correct. Controller by default is singleton and the injected testClass is instantiated once, because default scoped proxy mode is DEFAULT from spring doc.

    public abstract ScopedProxyMode proxyMode Specifies whether a component should be configured as a scoped proxy and if so, whether the proxy should be interface-based or subclass-based. Defaults to ScopedProxyMode.DEFAULT, which typically indicates that no scoped proxy should be created unless a different default has been configured at the component-scan instruction level.

    Analogous to support in Spring XML.

    See Also: ScopedProxyMode Default: org.springframework.context.annotation.ScopedProxyMode.DEFAULT

    if you want new instance to be injected every time you need, you should change your TestClass to :

    @Component
    @Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
    public class TestClass {
    
        public TestClass() {
            System.out.println("new test class constructed.");
        }
    
        public void doSomething() {
    
        }
    
    }
    

    with this additional configuration the injected testClass will not be really a TestClass bean but proxy to TestClass bean and this proxy will understand the prototype scope and will return new instance every time is needed.

    0 讨论(0)
  • 2021-02-05 04:41

    You cannot autowire prototype bean (well, you can but the bean will be always the same)... autowire the ApplicationContext and get an instance of the needed prototype bean manually (for example in the constructor):

        TestClass test = (TestClass) context.getBean("nameOfTestClassBeanInConfiguration");
    

    In this way you're sure of getting a new instance of TestClass.

    0 讨论(0)
  • 2021-02-05 04:41

    The key point hear is that the restController bean is a singleton and Spring will create only one instance of that bean during the creation of bean.

    When you impose a prototype bean scope Spring will instance a new bean for every DI point. In other words if you configure a bean a two or n-times via xml or java-config this bean will have a fresh instance of your prototype-scoped bean.

    In your case you use the annotation style that actually is the default way for web layer starting spring 3.x.

    One possibility to inject a fresh bean may be achieved with a bean scoped on the session, but in my opinion if your use case is a rest WS that I consider stateless, the session use in my opinion is a bad choice.

    A solution of your case may be use request scope.

    Update I write also just a simple example

         @SpringBootApplication
         public class DemoApplication {
    
            public static void main(String[] args) {
                SpringApplication.run(DemoApplication.class, args);
            }
    
            @Bean
            @Scope(scopeName = "request",proxyMode = ScopedProxyMode.TARGET_CLASS)
            public RequestBeanTest requestBeanTest(){
                return new RequestBeanTest();
            }
    
        }
    
        class RequestBeanTest {
            public RequestBeanTest(){
                Random random = new Random();
                System.out.println(random.nextGaussian());
                System.out.println("new object was created");
            }
    
            private String prop;
    
            public String execute(){
    
                return "hello!!!";
            }
    
            public String getProp() {
                return prop;
            }
    
            public void setProp(String prop) {
                this.prop = prop;
            }
        }
    
    
        @RestController
        class RestTemplateTest {
    
            @Autowired
            private RequestBeanTest requestBeanTest;
    
            @RequestMapping("/testUrl")
            public ResponseEntity responseEntity(){
                requestBeanTest.setProp("test prop");
    
                System.out.println(requestBeanTest.getProp());
                return ResponseEntity.ok(requestBeanTest.execute());
            }
        }
    

    the my pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
    
        <name>demo</name>
        <description>Demo project for Spring Boot</description>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.3.3.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    

    the bowser screen:

    and the my log screen:

    I don't know why it don't work for you probably you had forgot some configuration.

    I hope that this more detalied solution can help you to understand how solve the your problem

    0 讨论(0)
提交回复
热议问题