복붙노트

[SPRING] 프로토 타입 빈은 예상대로 자동 실행되지 않습니다.

SPRING

프로토 타입 빈은 예상대로 자동 실행되지 않습니다.

TestController.java

@RestController
public class TestController {

    @Autowired
    private TestClass testClass;

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

TestClass.java

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

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

    public void doSomething() {

    }

}

보시다시피 "xxx / test"방문시 새 TestClass가 주입되었는지 여부를 파악하려고합니다. "새로운 테스트 클래스가 생성되었습니다." 내가 똑같이 인쇄 할 것을 기대하면서 ( "xxx / test"를 처음으로 실행 한) 한 번만 인쇄되었습니다. 그것은 @Autowired 객체가 @Singleton 일 수 있다는 것을 의미합니까? 그렇다면 @Scope는 어떻게 작동합니까?

편집하다:

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

Scope (scopeName = "request")로 등록 된 @Valerio Vaudi 솔루션을 사용했습니다. 다음은 "xxx / test"를 방문했을 때의 세 가지 결과입니다.

(처음으로)

(둘째)

(제삼)

나는 그것을 사용할 때마다 새로운 것을 재구성하지 않기 때문에 왜 결과가 null인지 이해하지 못한다.

그런 다음 @ Nikolay Rusev 솔루션 @ Scope ( "프로토 타입")을 시도했습니다.

(먼저)

(둘째)

(제삼)

이것은 (TestClass) 사용할 때마다 이해하기 쉽습니다. 스프링은 새로운 인스턴스를 자동으로 재생성합니다. 하지만 각 요청마다 단 하나의 새로운 인스턴스 만 보유하고있는 것으로 보아 여전히 이해할 수없는 첫 번째 장면입니다.

실제 요구 사항은 다음과 같습니다. 각 요청주기마다 새 testClass가 필요하며 필요한 경우 하나만 필요합니다. 현재 ApplicationContext 솔루션 만이 가능할 것으로 보이지만 (@ 이미 알고있는), @Component + @Scope + @Autowired를 사용하여 자동으로이 작업을 수행 할 수 있는지 알고 싶습니다.

해결법

  1. ==============================

    1.위의 모든 대답은 정확합니다. 기본 스코프 프록시 모드는 스프링 박사의 DEFAULT이기 때문에 컨트롤러는 기본적으로 싱글 톤이며 주입 된 testClass는 한 번 인스턴스화됩니다.

    위의 모든 대답은 정확합니다. 기본 스코프 프록시 모드는 스프링 박사의 DEFAULT이기 때문에 컨트롤러는 기본적으로 싱글 톤이며 주입 된 testClass는 한 번 인스턴스화됩니다.

    필요에 따라 매번 새로운 인스턴스를 삽입하려면 TestClass를 다음과 같이 변경해야합니다.

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

    이 추가 구성으로 주입 된 testClass는 실제로 TestClass bean이 아니고 TestClass bean에 대한 프록시가되며이 프록시는 프로토 타입 범위를 이해하고 필요할 때마다 새 인스턴스를 리턴합니다.

  2. ==============================

    2.스프링 컨트롤러는 기본적으로 싱글 톤이며 다른 스프링 빈뿐만 아니라 스테이트리스 성 (stateless nature)으로 인해 좋다.

    스프링 컨트롤러는 기본적으로 싱글 톤이며 다른 스프링 빈뿐만 아니라 스테이트리스 성 (stateless nature)으로 인해 좋다.

    그렇기 때문에 유일한 TestController 인스턴스에 대해 하나의 TestClass 인스턴스 만 인스턴스화하는 것으로 충분합니다.

    한 번 더 TestClass를 인스턴스화하는 것은 쉽습니다 - 그냥 다른 컨트롤러에 삽입하거나 프로그래밍 방식으로 컨텍스트에서 가져 오기만하면됩니다.

  3. ==============================

    3.앞서 언급했듯이 컨트롤러는 기본적으로 싱글 톤이므로 TestClass를 인스턴스화하고 주입하는 작업이 한 번만 수행됩니다.

    앞서 언급했듯이 컨트롤러는 기본적으로 싱글 톤이므로 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();
        }
    }
    

    이제 TestClass bean이 요청되면 Spring은 @Prototype이라는 것을 알고 새로운 인스턴스를 생성하고 리턴한다.

    또 다른 해결책은 컨트롤러 @Scope ( "프로토 타입")를 만드는 것입니다.

  4. ==============================

    4.프로토 타입 bean을 autowire 할 수 없다. (물론 bean은 항상 같을 수있다.) ... ApplicationContext를 autowire하고 필요한 prototype bean의 인스턴스를 수동으로 얻는다. (예를 들어 생성자에서) :

    프로토 타입 bean을 autowire 할 수 없다. (물론 bean은 항상 같을 수있다.) ... ApplicationContext를 autowire하고 필요한 prototype bean의 인스턴스를 수동으로 얻는다. (예를 들어 생성자에서) :

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

    이 방법으로 TestClass의 새로운 인스턴스를 얻을 수 있습니다.

  5. ==============================

    5.중요한 요점은 restController 빈은 싱글 톤이고 Spring은 빈을 생성하는 동안 그 빈의 인스턴스를 하나만 생성한다는 것이다.

    중요한 요점은 restController 빈은 싱글 톤이고 Spring은 빈을 생성하는 동안 그 빈의 인스턴스를 하나만 생성한다는 것이다.

    프로토 타입 bean 스코프를 지정하면 Spring은 모든 DI 포인트에 대해 새 bean을 인스턴스화합니다. 즉, xml 또는 java-config를 통해 빈을 두 번 또는 n 번 구성하면이 빈은 프로토 타입 범위의 빈의 새로운 인스턴스를 갖게됩니다.

    귀하의 경우 스프링 3.x를 시작하는 웹 레이어의 기본 방법 인 주석 스타일을 사용합니다.

    신선한 콩을 주입 할 수있는 한 가지 가능성은 세션에서 범위가 지정된 빈을 사용하여 얻을 수 있지만 내 생각에 유스 케이스가 무명 상태로 간주되는 나머지 WS 인 경우 내 세션의 사용은 나쁜 선택입니다.

    케이스의 해결책은 사용 요청 범위 일 수 있습니다.

    최신 정보 간단한 예제도 쓴다.

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

    내 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>
    

    bowser 화면 :

    내 로그 화면 :

    나는 그것이 당신을 위해 왜 당신이 아마 어떤 구성을 잊어 버렸을 지 모르겠다.

    이보다 자세한 솔루션이 문제 해결 방법을 이해하는 데 도움이되기를 바랍니다.

  6. from https://stackoverflow.com/questions/36278595/prototype-bean-doesnt-get-autowired-as-expected by cc-by-sa and MIT license