[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.위의 모든 대답은 정확합니다. 기본 스코프 프록시 모드는 스프링 박사의 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.스프링 컨트롤러는 기본적으로 싱글 톤이며 다른 스프링 빈뿐만 아니라 스테이트리스 성 (stateless nature)으로 인해 좋다.
스프링 컨트롤러는 기본적으로 싱글 톤이며 다른 스프링 빈뿐만 아니라 스테이트리스 성 (stateless nature)으로 인해 좋다.
그렇기 때문에 유일한 TestController 인스턴스에 대해 하나의 TestClass 인스턴스 만 인스턴스화하는 것으로 충분합니다.
한 번 더 TestClass를 인스턴스화하는 것은 쉽습니다 - 그냥 다른 컨트롤러에 삽입하거나 프로그래밍 방식으로 컨텍스트에서 가져 오기만하면됩니다.
-
==============================
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.프로토 타입 bean을 autowire 할 수 없다. (물론 bean은 항상 같을 수있다.) ... ApplicationContext를 autowire하고 필요한 prototype bean의 인스턴스를 수동으로 얻는다. (예를 들어 생성자에서) :
프로토 타입 bean을 autowire 할 수 없다. (물론 bean은 항상 같을 수있다.) ... ApplicationContext를 autowire하고 필요한 prototype bean의 인스턴스를 수동으로 얻는다. (예를 들어 생성자에서) :
TestClass test = (TestClass) context.getBean("nameOfTestClassBeanInConfiguration");
이 방법으로 TestClass의 새로운 인스턴스를 얻을 수 있습니다.
-
==============================
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 화면 :
내 로그 화면 :
나는 그것이 당신을 위해 왜 당신이 아마 어떤 구성을 잊어 버렸을 지 모르겠다.
이보다 자세한 솔루션이 문제 해결 방법을 이해하는 데 도움이되기를 바랍니다.
from https://stackoverflow.com/questions/36278595/prototype-bean-doesnt-get-autowired-as-expected by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 봄 3 + 석영 2 오류 (0) | 2019.03.18 |
---|---|
[SPRING] gradle 작업을 통해 spring 프로필로 bootRun을 실행하는 방법 (0) | 2019.03.18 |
[SPRING] Spring Boot RestController에서 요청 URL을 얻는 방법 (0) | 2019.03.18 |
[SPRING] Spring 3.2와 Cache Abstraction에서 EhCache 구현이 누락되었습니다. (0) | 2019.03.18 |
[SPRING] 외부화 된 값을 Spring annotation으로 주입 (0) | 2019.03.18 |